定義:一個軟件實體如類零渐、模塊和函數(shù)應該對擴展開放窒舟,對修改關(guān)閉。
也就是說相恃,如果修改或者添加一個功能辜纲,應該是通過擴展原來的代碼笨觅,而不是通過修改原來的代碼拦耐。
比如,在圖片加載類中见剩,有內(nèi)存緩存杀糯,磁盤緩存,還有雙緩存:
//內(nèi)存緩存
public class MemoryCache {
LruCache<String, Bitmap> mLruCache;
public MemoryCache() {
int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
int cacheSize = maxMemory / 4;
mLruCache = new LruCache<String, Bitmap>(cacheSize) {
@Override
protected int sizeOf(String key, Bitmap value) {
return value.getRowBytes() * value.getHeight() / 1024;
}
};
}
public Bitmap get(String url) {
return return mLruCache.get(url);
}
public void put(String url, Bitmap bmp) {
// do something
}
}
//磁盤緩存
public class DiskCache {
public Bitmap get(String url) {
return BitmapFactory.decodeFile(url);
}
public void put(String url, Bitmap bmp) {
//do something
}
}
//雙緩存
public class DoubleCache {
MemoryCache mMemoryCache = new MemoryCache();
DiskCache mDiskCache = new DiskCache();
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) {
//do something
}
}
如果不用開閉原則苍苞,那么在圖片加載類中固翰,可能會這么寫:
public class ImageLoader {
MemoryCache mMemoryCache = new MemoryCache();
DiskCache mDiskCache = new DiskCache();
DoubleCache mDoubleCache = new DoubleCache();
boolean isDiskCache = false; //使用磁盤緩存
boolean isDoubleCache = false; //使用雙緩存
public ImageLoader() {
}
public void displayImage(String url, ImageView mImageView) {
Bitmap bitmap = null;
if (isDoubleCache) {
bitmap = mDoubleCache.get(url);
} else if (isDiskCache) {
bitmap = mDiskCache.get(url);
} else {
bitmap = mMemoryCache.get(url);
}
if (bitmap != null) {
mImageView.setImageBitmap(bitmap);
} else {
//沒有緩存,下載圖片
}
}
public void setDiskCache(boolean diskCache) {
isDiskCache = diskCache;
}
public void setDoubleCache(boolean doubleCache) {
isDoubleCache = doubleCache;
}
}
這樣寫羹呵,可能會出現(xiàn)這樣的問題:
if-else 的判斷條件太多骂际,如果寫錯了其中一個,就會化很多時間去查找和解決冈欢,ImageLoader 類也會變得臃腫歉铝,而且用戶不能自己實現(xiàn)緩存注入到 ImageLoader 中,可擴展性差凑耻。
那么太示,通過分析可以知道,每個緩存都用 set 和 put 方法香浩,那么可以把它抽象出來类缤。
UML圖:
這樣通過接口就可以實現(xiàn)不同的緩存,而且不需要改變 ImageLoader 的代碼邻吭。
首先創(chuàng)建接口 ImageCache:
public interface ImageCache {
void put(String url, Bitmap bmp);
Bitmap get(String url);
}
然后將原來的三種緩存都繼承它:
//內(nèi)存緩存
public class MemoryCache implements ImageCache {
LruCache<String, Bitmap> mLruCache;
public MemoryCache() {
//初始化LruCache
}
@Override
public void put(String url, Bitmap bmp) {
mLruCache.put(url, bmp);
}
@Override
public Bitmap get(String url) {
return mLruCache.get(url);
}
}
//磁盤緩存
public class DiskCache implements ImageCache{
@Override
public void put(String url, Bitmap bmp) {
//將Bitmap寫入文件
}
@Override
public Bitmap get(String url) {
return BitmapFactory.decodeFile(url); //從文件中獲取Bitmap
}
}
//雙緩存
public class DoubleCache implements ImageCache {
ImageCache mMemoryCache = new MemoryCache();
ImageCache mDiskCache = new DiskCache();
@Override
public void put(String url, Bitmap bmp) {
mMemoryCache.put(url, bmp);
mDiskCache.put(url, bmp);
}
@Override
public Bitmap get(String url) {
Bitmap bitmap = mMemoryCache.get(url);
if (bitmap == null) {
bitmap = mDiskCache.get(url);
}
return bitmap;
}
}
那么餐弱,ImageLoader 類就可以改寫成:
public class ImageLoader {
ImageCache mImageCache = new MemoryCache();
public void setImageCache(ImageCache imageCache) {
mImageCache = imageCache;
}
public ImageLoader() {
}
public void displayImage(String url, ImageView mImageView) {
Bitmap bitmap = mImageCache.get(url);
if (bitmap != null) {
mImageView.setImageBitmap(bitmap);
}
//圖片沒緩存,下載
// do something
}
}
比原來的簡潔很多囱晴。
那么在使用的時候這樣:
ImageLoader imageLoader = new ImageLoader();
//選擇使用內(nèi)存緩存
imageLoader.setImageCache(new MemoryCache());
//選擇使用磁盤緩存
imageLoader.setImageCache(new DiskCache());
//選擇使用雙緩存
imageLoader.setImageCache(new DoubleCache());
//不選擇封裝好的緩存膏蚓,自己實現(xiàn)緩存
imageLoader.setImageCache(new ImageCache() {
@Override
public void put(String url, Bitmap bmp) {
}
@Override
public Bitmap get(String url) {
return null;
}
});
可以看到,用戶通過 setImageCache 方法可以自由設(shè)置緩存的實現(xiàn)方式速缆,而不用通過修改 ImageLoader 來實現(xiàn)降允。setImageCache 就是通常說的依賴注入。使得 ImageLoader 類更加健壯艺糜,這就是開閉原則剧董。
這里幢尚,應該明白開閉原則是怎么一回事了。
參考:《Android源碼設(shè)計模式解析與實踐》