面向對象六大原則之單一職責原則

前言

從開始接觸面向對象開始就有對面向對象原則的了解,到目前為止也多次看到,可每次看到的時候,都有種似曾相識卻又驚嘆無比的感覺,這樣的感覺明顯是不對的,學完一些知識應該是融匯貫通于你的思想之中,然后穿過你的身體,穿過你的靈魂再展現出來,所以我們要躬行于知識的沃土之上,讓那些讓規律,想法,知識,真正能穿過我們的靈魂,我們的身體,然后再表達出來,基于此,我也想記錄一下我的所學,所知!

定義

單一職責原則的英文名稱是 Single Responsibility Principle,簡稱SRP,它的定義是:就一個類而言,應該僅有一個引起它變化的原因。也就是說,一個類中應該是一組相關性很高的函數、數據的封裝。

應用

舉個栗子

比如這樣一個需求,寫一個圖片加載類,實現圖片加載,并且要將圖片緩存起來。

實現如下:

/**
 * 圖片加載類
 */
public class ImageLoader {
    //圖片緩存
    LruCache<String,Bitmap> mImageCache;
    //線程池,線程數量為CPU的數量
    ExecutorService mExecutorService = Executors.newFixedThreadPool(
            Runtime.getRuntime().availableProcessors());
    public ImageLoader(){
        initImageCache();
    }

    private void initImageCache() {
        //計算可使用的最大內存
        final int maxMemory = (int)(Runtime.getRuntime().maxMemory() / 1024);
        //取四分之一的可用內存作為緩存
        final int cacheSize = maxMemory / 4;
        mImageCache = new LruCache<String,Bitmap>(cacheSize){
            @Override
            protected int sizeOf(String key, Bitmap value) {
                return value.getRowBytes() * value.getHeight() / 1024;
            }
        };
    }
    public void displayImage(final String url, final ImageView imageView) {
        imageView.setTag(url);
        mExecutorService.submit(new Runnable() {
            @Override
            public void run() {
                Bitmap bitmap = downloadImage(url);
                if (bitmap == null) {
                    return;
                }
                if (imageView.getTag().equals(url)) {
                    imageView.setImageBitmap(bitmap);
                }
                mImageCache.put(url,bitmap);
            }
        });
    }
    private Bitmap downloadImage(String imageUrl) {
        Bitmap bitmap = null;
        try {
            URL url = new URL(imageUrl);
            final HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            bitmap = BitmapFactory.decodeStream(conn.getInputStream());
            conn.disconnect();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return bitmap;
    }

}

我們來分析一下這個類,功能上是沒有問題的,但把緩存功能的邏輯也雜糅到圖片加載類中,這明顯不符合單一職責原則,更不要說擴展性、靈活性了,這樣隨著功能的增加,ImageLoader類只會越來越復雜。

那我們考慮一下怎么解耦?
那我們想一下,如果把圖片緩存相關代碼剝離出去怎么做。
我們可以把上面代碼中緩存圖片的LruCache對象交給一個專門的圖片緩存類處理,類圖如下

對應代碼如下:

/**
 * 圖片緩存類
 */
public class ImageCache {
    //圖片LRU緩存
    LruCache<String,Bitmap> mImageCache;
    public ImageCache() {
        initImageCache();
    }

    private void initImageCache() {
        //計算可使用的最大內存
        final int maxMemory = (int)(Runtime.getRuntime().maxMemory() / 1024);
        //取四分之一的可用內存作為緩存
        final int cacheSize = maxMemory / 4;
        mImageCache = new LruCache<String,Bitmap>(cacheSize){
            @Override
            protected int sizeOf(String key, Bitmap value) {
                return value.getRowBytes() * value.getHeight() / 1024;
            }
        };
    }
    public void put (String url,Bitmap bitmap) {
        mImageCache.put(url,bitmap);
    }
    public Bitmap get(String url) {
        return mImageCache.get(url);
    }
}

/**
 * 圖片加載類
 */
public class ImageLoader {
    //圖片緩存
    ImageCache mImageCache = new ImageCache();
    //線程池,線程數量為CPU的數量
    ExecutorService mExecutorService = Executors.newFixedThreadPool(
            Runtime.getRuntime().availableProcessors());

    public void displayImage(final String url, final ImageView imageView) {
        Bitmap bitmap = mImageCache.get(url);
        if (bitmap != null) {
            imageView.setImageBitmap(bitmap);
            return;
        }
        imageView.setTag(url);
        mExecutorService.submit(new Runnable() {
            @Override
            public void run() {
                Bitmap bitmap = downloadImage(url);
                if (bitmap == null) {
                    return;
                }
                if (imageView.getTag().equals(url)) {
                    imageView.setImageBitmap(bitmap);
                }
                mImageCache.put(url,bitmap);
            }
        });
    }
    private Bitmap downloadImage(String imageUrl) {
        Bitmap bitmap = null;
        try {
            URL url = new URL(imageUrl);
            final HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            bitmap = BitmapFactory.decodeStream(conn.getInputStream());
            conn.disconnect();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return bitmap;
    }
}

如上述代碼,把ImageLoader一拆為二,ImageLoader只負責圖片加載的邏輯,ImageCache負責圖片處理的邏輯,這樣ImageLoader類的代碼少了,職責也清晰了,當與緩存相關的需求需要改變時我們只需更改ImageCache類就可以了,當與加載圖片需求需要改變時我們只需修改ImageLoader類即可,但此類的擴展靈活性也有所欠缺(此處涉及到開面向對象的另一個原則-開閉原則)

單一職責原則,主要就是單一兩個字,也就是說 多個不一樣的功能不應該放到一個類中,一個類應該是一組相關性很高的函數、數據的封裝。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容