我的理解:開閉原則

定義:一個軟件實體如類、模塊和函數(shù)應(yīng)該對擴(kuò)展開放,對修改關(guān)閉。
也就是說,如果修改或者添加一個功能,應(yīng)該是通過擴(kuò)展原來的代碼,而不是通過修改原來的代碼。

比如,在圖片加載類中,有內(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 中,可擴(kuò)展性差。

那么,通過分析可以知道,每個緩存都用 set 和 put 方法,那么可以把它抽象出來。
UML圖:

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 類更加健壯,這就是開閉原則。

這里,應(yīng)該明白開閉原則是怎么一回事了。

參考:《Android源碼設(shè)計模式解析與實踐》

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 本文出自《Android源碼設(shè)計模式解析與實戰(zhàn)》中的第一章。 1、優(yōu)化代碼的第一步——單一職責(zé)原則 單一職責(zé)原則的...
    MrSimp1e0閱讀 1,919評論 1 13
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,351評論 25 708
  • 最新在閱讀《Android源碼設(shè)計模式解析與實戰(zhàn)》一書,我覺得寫的很清晰,每一個知識點都有示例,通過示例更加容易理...
    慕涵盛華閱讀 2,469評論 0 3
  • 昨天發(fā)布的2017胡潤全球富豪榜中,在全球十億美金富豪里,女性占比15%,其中121位來自中國。同樣的,創(chuàng)業(yè)邦用2...
    JulienYu閱讀 1,905評論 5 10
  • 01給你舞臺并不是一定要你跳舞 其實今天一共四個部分,有兩個部分是不愉快的事件引發(fā)的。首先第一個的故事是這樣的,我...
    JeffreyShu閱讀 239評論 0 0

友情鏈接更多精彩內(nèi)容