前言
從開始接觸面向對象開始就有對面向對象原則的了解,到目前為止也多次看到,可每次看到的時候,都有種似曾相識卻又驚嘆無比的感覺,這樣的感覺明顯是不對的,學完一些知識應該是融匯貫通于你的思想之中,然后穿過你的身體,穿過你的靈魂再展現出來,所以我們要躬行于知識的沃土之上,讓那些讓規律,想法,知識,真正能穿過我們的靈魂,我們的身體,然后再表達出來,基于此,我也想記錄一下我的所學,所知!
定義
單一職責原則的英文名稱是 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類即可,但此類的擴展靈活性也有所欠缺(此處涉及到開面向對象的另一個原則-開閉原則)
單一職責原則,主要就是單一兩個字,也就是說 多個不一樣的功能不應該放到一個類中,一個類應該是一組相關性很高的函數、數據的封裝。