開閉原則(Open Closed Principle)是Java世界里最基礎(chǔ)的設(shè)計原則,它指導(dǎo)我們?nèi)绾谓⒁粋€穩(wěn)定的、靈活的系統(tǒng)。
定義:一個軟件實體如類、模塊和函數(shù)應(yīng)該對擴展開放,對修改關(guān)閉。
簡單的說就是在修改需求的時候,應(yīng)該盡量通過擴展來實現(xiàn)變化,而不是通過修改已有代碼來實現(xiàn)變化。
舉一個簡單的例子:
在圖片加載器ImageLoder中,我們需要將圖片緩存來加快軟件速度和節(jié)約用戶流量。我們一開始可能會考慮將從網(wǎng)絡(luò)上獲取到的圖片加載到內(nèi)存中去,并在第二次需要加載此圖片時直接從內(nèi)存中獲取。
于是,我們創(chuàng)建一個MemoryCache類。
注意:下面代碼只是模擬,省略了具體實現(xiàn)
//ImageLoder類 ,用于圖片加載
public class ImageLoder {
//內(nèi)存緩存類
MemoryCache mMemoryCache;
//加載圖片
public void displayImage(final String url, final ImageView imageView, Context context) {
//使用緩存
useCache(String url,mMemoryCache);
}
private void useCache(String url,MemoryCache mMemoryCache){
//從內(nèi)存中去獲取
Bitmap bitmap= mMemoryCache.get( url);
//如果內(nèi)存中沒有就通過網(wǎng)絡(luò)下載
if(bitmap==null){
//開啟線程,從網(wǎng)上下載圖片
bitmap=downloadBitmap();
}
//將圖片存入內(nèi)存緩存
mMemoryCache.put(url);
}
}
//MemoryCache 內(nèi)存緩存類
public class MemoryCache {
/*
** 省略具體實現(xiàn),具體實現(xiàn)使用LruCache類
* put()方法用來將圖片存入緩存。
* get()用于從緩存中取出圖片
*/
public void put(String url, Bitmap bitmap) {
/*
** 省略具體實現(xiàn)
*/
}
public Bitmap get(String url) {
/*
** 省略具體實現(xiàn)
*/
}
}
上面的MemoryCache 解決了每次從網(wǎng)上下載圖片的問題,但是Android 內(nèi)存有限。<font color=red face=“黑體”>單個應(yīng)用的最大內(nèi)存可以這樣獲?。篟untime.getRuntime().maxMemory()</font> 并且,具有易失性,即每次應(yīng)用重啟后,原來加載的圖片都會丟失,這樣又得從網(wǎng)絡(luò)下載。所以,我們考慮加入一個SD卡緩存類。這樣下載的圖片將緩存到本地。
//DiskCache sd卡緩存類
public class DiskCache {
/*
** 省略具體實現(xiàn)
* put()方法用來將圖片存入緩存。
* get()用于從緩存中取出圖片
*/
public Bitmap get(String url) {
/*
** 省略具體實現(xiàn)
*/
}
public void put(String url, Bitmap bitmap) {
/*
** 省略具體實現(xiàn)
*/
}
}
下面是修改后的ImageLoder類
public class ImageLoder {
//內(nèi)存緩存類
MemoryCache mMemoryCache;
//sd卡緩存類
DiskCache mDiskCache;
//用于判斷是否用MemoryCache,默認使用
boolean isUseMemoryCache = true;
//加載圖片
public void displayImage(final String url, final ImageView imageView, Context context) {
//根據(jù)useMemoryCahce來判斷Cache使用的類型
if(useMemoryCahce){
useMemoryCache(String url,mMemoryCache);
}else{
useDiskCache(String url,mMemoryCache);
}
}
//使用MemoryCache
private void useMemoryCache(String url,MemoryCache mMemoryCache){
Bitmap bitmap= mMemoryCache.get( url);
if(bitmap==null){
//開啟線程,從網(wǎng)上下載圖片
bitmap=downloadBitmap();
}
//將圖片存入內(nèi)存緩存
mMemoryCache.put(url);
}
//使用DiskCache
private void useDiskCache(String url,DiskCache mDiskCache){
Bitmap bitmap= mDiskCache.get( url);
if(bitmap==null){
//開啟線程,從網(wǎng)上下載圖片
bitmap=downloadBitmap();
}
//將圖片存入內(nèi)存緩存
mDiskCache.put(url);
}
//獲取isUseMemoryCache
private boolean useMemoryCahce(){
return isUseMemoryCache ;
}
//設(shè)置isUseMemoryCache
private void SetUseMemoryCache(boolean isUseMemoryCache){
this.isUseMemoryCache =isUseMemoryCache ;
}
}
在上面的代碼中,我們修改了 ImageLoader類,通過useMemoryCahce()方法來判斷使用哪一類型的cache.可以看到我們加入了一個if else語句來實現(xiàn)緩存的選擇功能。但是如果日后將cache的類型增加到十個甚至幾十個的時候,我們便需要再修改ImageLoder類,增加它的if else語句。在修改中可能會因各種因素使我們發(fā)生不必要的錯誤。顯然這不符合OCP原則。
有沒有什么方法可以讓我們擺脫if - else 語句(有人說用switch語句....這個這個)或者說讓我們不改動ImageLoader類來實現(xiàn)新功能呢?
答案肯定是有的。
下面我們使用接口來實現(xiàn)下上面的功能,給出一個uml類圖。
不會看UML類圖的請參考 5分鐘學會看UML類圖
在上圖中,創(chuàng)建了一個接口類,所有Cache類都實現(xiàn)該接口并重寫put 和get 方法。并增加了setImageCache(ImageCache mImageCache)方法用于用戶自定義cache類型,而一旦有新的cache類型產(chǎn)生的時候,只需要實現(xiàn)ImageCache接口,然后調(diào)用setImageCache方法即可實現(xiàn)并使用新cache類型。符合OCP的原則。
下面是重構(gòu)后的類。
//接口類
public interface ImageCache {
public Bitmap get(String url);
public void put(String url, Bitmap bitmap);
}
//MemoryCache 內(nèi)存緩存類
public class MemoryCache implements ImageCache {
/*
** 省略具體實現(xiàn),具體實現(xiàn)使用LruCache類
* put()方法用來將圖片存入緩存。
* get()用于從緩存中取出圖片
*/
public void put(String url, Bitmap bitmap) {
/*
** 省略具體實現(xiàn)
*/
}
public Bitmap get(String url) {
/*
** 省略具體實現(xiàn)
*/
}
}
//DiskCache sd卡緩存類
public class DiskCache implements ImageCache {
/*
** 省略具體實現(xiàn)
* put()方法用來將圖片存入緩存。
* get()用于從緩存中取出圖片
*/
public Bitmap get(String url) {
/*
** 省略具體實現(xiàn)
*/
}
public void put(String url, Bitmap bitmap) {
/*
** 省略具體實現(xiàn)
*/
}
}
//ImageLoder類 ,用于圖片加載
public class ImageLoder {
//默認使用內(nèi)存緩存類,也可以是其他Cache
ImageCache cache = new MemoryCache();
//用于自定義Cache類型
public void setImageCache(ImageCache mImageCache) {
this.mImageCache = mImageCache;
}
//加載圖片
public void displayImage(final String url, final ImageView imageView, Context context) {
//使用緩存
useCache(String url,mImageCache);
}
private void useCache(String url,ImageCachemImageCache){
Bitmap bitmap= mImageCache.get(url);
if(bitmap==null){
//開啟線程,從網(wǎng)上下載圖片
bitmap=downloadBitmap();
}
//將圖片存入內(nèi)存緩存
mImageCache.put(url);
}
}
開閉原則:當軟件需要修改時應(yīng)盡量通過擴展的方式來實現(xiàn),并不是說一定不能通過修改已有的代碼來實現(xiàn)。具體是否使用應(yīng)該由當前項目具體情況具體分析。