簡(jiǎn)介
這周入手了《Android源碼設(shè)計(jì)模式解析與實(shí)戰(zhàn)》,將花一段時(shí)間去閱讀并做上讀書(shū)筆記。本書(shū)的第一章介紹了面向?qū)ο蟮牧笤瓌t,這篇文章先介紹前兩條:?jiǎn)我宦氊?zé)原則和開(kāi)閉原則,并觀察書(shū)中所舉的例子,一個(gè)寫(xiě)的不錯(cuò)的圖片加載器,來(lái)看看作者是怎么用代碼詮釋著兩大原則的。
單一職責(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ù)的封裝。
試想一下,如果所有的功能寫(xiě)在一個(gè)類里,那么這個(gè)類會(huì)越來(lái)越大,越來(lái)越復(fù)雜,越不易修改維護(hù)。那么根據(jù)功能,各自獨(dú)立拆分出來(lái),豈不是邏輯會(huì)清晰些。比如作者給的例子是一個(gè) ImageLoder 類,和一個(gè) ImageCache 類。
public class ImageCache{
//只負(fù)責(zé)圖片緩存邏輯
}
public class ImageLoader {
//只負(fù)責(zé)圖片的加載邏輯
}
開(kāi)閉原則 (OCP)#
軟件中的對(duì)象(類、模塊、函數(shù)等)應(yīng)該對(duì)于擴(kuò)展是開(kāi)放的,但是對(duì)于修改是封閉的。當(dāng)軟件需要變化時(shí),我們應(yīng)該盡量通過(guò)擴(kuò)展的方式實(shí)現(xiàn)變化,而不是通過(guò)修改原有的代碼來(lái)實(shí)現(xiàn)。因?yàn)橹苯拥男薷?,可能?huì)影響已有的正常代碼。不利于出現(xiàn)錯(cuò)誤時(shí)排除問(wèn)題。當(dāng)然實(shí)際開(kāi)發(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è)接口后,無(wú)論是想用內(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)存緩存中獲取圖片,如果沒(mé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;
}
用戶可以通過(guò) setmImageCache(ImageCache cache) 方法注入不同的緩存實(shí)現(xiàn),這樣不僅能夠使 ImageLoder 更簡(jiǎn)單、健壯,也使得 ImageLoder 的可擴(kuò)展性、靈活性更高。三個(gè)緩存圖片的具體實(shí)現(xiàn)完全不同,但他們都實(shí)現(xiàn)了 ImageCache 接口,就都可以通過(guò) setmImageCache 方法注入到 ImageLoder 中,這樣 ImageLoder 就實(shí)現(xiàn)了千變?nèi)f化的緩存策略。