面向對象六大原則(一):單一職責原則

一、簡介


單一職責原則(Single Responsibility Principle,縮寫:SRP),它規定一個類應該只有一個引起它發生變化的原因,也就是一個類中應該是一組相關性很高的函數、數據的封裝。

二、原理

如果一個類承擔的職責過多,就等於把這些職責耦合在一起了。一個職責的變化可能會削弱或者抑制這個類完成其他職責的能力。這種耦合會導致脆弱的設置,當發生變化時,設計會遭受到意想不到的破壞。如果要想避免這種現象的發生,就要儘可能的遵守單一職責原則。此原則的核心就是解耦和增強內聚性。

三、解決辦法

遵守單一職責原則,將不同的職責封裝到不同的類和模塊中。下面引用《Android源碼設計模式解析與實戰》一書中圖片加載器(ImageLoader)的代碼例子:

1.初始代碼

/**
 * 圖片加載類
 */
public class ImageLoader {
    //圖片緩存
    LruCache<String, Bitmap> mImageCache;
    //線程池
    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 bitmap) {
                return bitmap.getRowBytes() * bitmap.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);
            }
        });
    }

    public 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;
    }
}

2.重構代碼:將ImageLoader一拆爲二,ImageLoader只負責圖片加載,ImageCache只負責處理圖片緩存的邏輯;這樣,當與緩存相關的邏輯需要改變時,不需要修改ImageLoader類,而圖片加載的邏輯需要修改時也不會影響到緩存處理邏輯。

(1)ImageLoader:

/**
 * 圖片加載類
 */
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);
            }
        });
    }

    public 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;
    }
}

(2)ImageCache:處理圖片緩存

public class ImageCache {
    //圖片緩存
    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 bitmap) {
                return bitmap.getRowBytes() * bitmap.getHeight() / 1024;
            }
        };
    }

    public void put(String url, Bitmap bitmap){
        mImageCache.put(url, bitmap);
    }

    public Bitmap get(String url){
        return mImageCache.get(url);
    }
}

四、分析

這是優化代碼的第一步。一個類,只有一個引起它變化的原因。應該只有一個職責。每一個職責都是變化的一個軸線,如果一個類有一個以上的職責,這些職責就耦合在了一起。這會導致脆弱的設計。當一個職責發生變化時,可能會影響其他的職責。另外,多個職責耦合在一起,會影響複用性。例如:要實現邏輯和界面的分離。 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章