面向對象的六大原則(一)——單一職責原則(切合Android,ImageLoader)

閱讀《Android源碼設計模式解析用於實戰》後的記錄

一:單一職責原則(Single Responsibility Principle)

顧名思義,就一個類而言,應該僅有一個引起它變化的原因。簡單的說,一個類中應該是一組相關性很高的函數、數據的封裝。

    以圖片加載器ImageLoader作爲示例。面向對象設計,那麼就必須考慮到可擴展性、靈活性。
    需求:實現圖片加載,並且要將圖片緩存起來。

問題代碼一:
/**
 * 圖片加載類
 */
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 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 = newURL(imageUrl);
            final HttpURLConnection conn = (HttpURLConnection) 
                            url.openConnection();
            bitmap = BitmapFactory.decodeStream(conn.getInputStream());
            conn.disconnect();
        } catch (Exception e) {
            e.printStackTrace();
        }

        return bitmap;
    }
}

這個ImageLoader.java雖然實現了基本功能,但是程序的耦合性太強,無擴展性,無靈活性。所有的功能都寫在一個類裏怎麼行呢,這樣隨着功能的增多,ImageLoader類會越來越大,代碼也越來越複雜,圖片加載系統就越來越脆弱。用單一職責原則進行第一步優化:

這裏寫圖片描述

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

並且添加了一個ImageCache類用於處理圖片緩存,具體代碼如下:

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

將ImageLoader一拆爲二,ImageLoader只負責圖片加載的邏輯,而ImageCache只負責處理圖片緩存的邏輯,這樣ImageLoader的代碼量變少了,職責也清晰了,當與緩存相關的邏輯需要改變時,不需要修改ImageLoader類,而圖片加載的邏輯需要修改時也不會影響到緩存處理邏輯。

如何劃分一個類、一個函數的職責,每個人都有自己的看法,這需要根據個人經驗、具體的業務邏輯而定。但是,它也有一些基本的指導原則,例如,兩個完全不一樣的功能就不應該放在一個類中。一個類中應該是一組相關性很高的函數、數據的封裝。工程師可以不斷地審視自己的代碼,根據具體的業務、功能對類進行相應的拆分,我想這會是你優化代碼邁出的第一步。

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