簡(jiǎn)介
這周入手了《Android源碼設(shè)計(jì)模式解析與實(shí)戰(zhàn)》朗兵,將花一段時(shí)間去閱讀并做上讀書筆記述寡。本書的第一章介紹了面向?qū)ο蟮牧笤瓌t柿隙,這篇文章先介紹前兩條:?jiǎn)我宦氊?zé)原則和開閉原則,并觀察書中所舉的例子鲫凶,一個(gè)寫的不錯(cuò)的圖片加載器禀崖,來看看作者是怎么用代碼詮釋著兩大原則的。
單一職責(zé)原則(SRP)
單一職責(zé)所表達(dá)出的用意就是 "單一" 二字螟炫。如何劃分一個(gè)類波附、一個(gè)函數(shù)的職責(zé),每個(gè)人都有自己的看法昼钻,這需要根據(jù)個(gè)人經(jīng)驗(yàn)叶雹、具體的業(yè)務(wù)邏輯而定。但是换吧,它也有一些基本的指導(dǎo)原則,例如钥星,兩個(gè)完全不一樣的功能就不應(yīng)該放在一個(gè)類中沾瓦。一個(gè)類中應(yīng)該是一組相關(guān)性很高的函數(shù)、數(shù)據(jù)的封裝谦炒。
試想一下贯莺,如果所有的功能寫在一個(gè)類里,那么這個(gè)類會(huì)越來越大宁改,越來越復(fù)雜缕探,越不易修改維護(hù)。那么根據(jù)功能还蹲,各自獨(dú)立拆分出來爹耗,豈不是邏輯會(huì)清晰些。比如作者給的例子是一個(gè) ImageLoder 類谜喊,和一個(gè) ImageCache 類潭兽。
public class ImageCache{
//只負(fù)責(zé)圖片緩存邏輯
}
public class ImageLoader {
//只負(fù)責(zé)圖片的加載邏輯
}
開閉原則 (OCP)#
軟件中的對(duì)象(類、模塊斗遏、函數(shù)等)應(yīng)該對(duì)于擴(kuò)展是開放的山卦,但是對(duì)于修改是封閉的。當(dāng)軟件需要變化時(shí)诵次,我們應(yīng)該盡量通過擴(kuò)展的方式實(shí)現(xiàn)變化账蓉,而不是通過修改原有的代碼來實(shí)現(xiàn)枚碗。因?yàn)橹苯拥男薷模赡軙?huì)影響已有的正常代碼铸本。不利于出現(xiàn)錯(cuò)誤時(shí)排除問題肮雨。當(dāng)然實(shí)際開發(fā)中,修改原有代碼與擴(kuò)展代碼是同時(shí)存在的归敬。但應(yīng)盡量以擴(kuò)展為主酷含。
為了使程序更利于擴(kuò)展,作者將之前的 ImageCache改造成了一個(gè)接口
/**
* 圖片緩存接口
*/
public interface ImageCache {
public Bitmap get(String url);
public void put(String url, Bitmap bmp);
}
定義了這樣一個(gè)接口后汪茧,無論是想用內(nèi)存緩存椅亚、SD卡緩存還是雙緩存都只需要實(shí)現(xiàn)該接口即可。我們看看這幾個(gè)緩存的實(shí)現(xiàn):
/**
* 內(nèi)存緩存MemoryCache類
*/
public class MemoryCache implements ImageCache {
private LruCache<String, Bitmap> mMemeryCache;
public MemoryCache() {
initLruCache();
}
//初始化LRU緩存
private void initLruCache() {
//計(jì)算可使用的最大內(nèi)存
final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
//取出1/4的內(nèi)存作為緩存
final int cacheSize = maxMemory / 4;
mMemeryCache = new LruCache<String, Bitmap>(cacheSize) {
@Override protected int sizeOf(String key, Bitmap value) {
return value.getRowBytes() * value.getHeight() / 1024;
}
};
}
@Override public Bitmap get(String url) {
return mMemeryCache.get(url);
}
@Override public void put(String url, Bitmap bmp) {
mMemeryCache.put(url, bmp);
}
}
/**
* 將圖片緩存到SD卡中
*/
public class DiskCache implements ImageCache {
static String cacheDir = "sdcard/cache/";
//從緩存中獲取圖片
public Bitmap get(String url) {
return BitmapFactory.decodeFile(cacheDir + url);
}
//將圖片存到內(nèi)存中
public void put(String url, Bitmap bmp) {
FileOutputStream fileOutputStream = null;
try {
fileOutputStream = new FileOutputStream(cacheDir + url);
//30 是壓縮率舱污,表示壓縮70%; 如果不壓縮是100呀舔,表示壓縮率為0
bmp.compress(Bitmap.CompressFormat.PNG, 100, fileOutputStream);
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
if (fileOutputStream != null) {
try {
fileOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
/**
* 雙緩存
*/
public class DoubleCache implements ImageCache {
ImageCache mMemoryCache = new MemoryCache();
DiskCache mDiskCache = new DiskCache();
//先從內(nèi)存緩存中獲取圖片,如果沒有就從SD卡中獲取
public Bitmap get(String url) {
Bitmap bitmap = mMemoryCache.get(url);
if (bitmap == null) {
bitmap = mDiskCache.get(url);
}
return bitmap;
}
public void put(String url, Bitmap bmp) {
mMemoryCache.put(url, bmp);
mDiskCache.put(url, bmp);
}
}
在 ImageLoder 中只需要做如下一個(gè)小小的改動(dòng)
public void setmImageCache(ImageCache cache) {
mImageCache = cache;
}
用戶可以通過 setmImageCache(ImageCache cache) 方法注入不同的緩存實(shí)現(xiàn)扩灯,這樣不僅能夠使 ImageLoder 更簡(jiǎn)單媚赖、健壯,也使得 ImageLoder 的可擴(kuò)展性珠插、靈活性更高惧磺。三個(gè)緩存圖片的具體實(shí)現(xiàn)完全不同,但他們都實(shí)現(xiàn)了 ImageCache 接口捻撑,就都可以通過 setmImageCache 方法注入到 ImageLoder 中磨隘,這樣 ImageLoder 就實(shí)現(xiàn)了千變?nèi)f化的緩存策略。