單一職責原則(SRP)又稱單一功能原則,為面向?qū)ο罅蠡驹瓌t之一。
我們先來看一下官方是如何描述該原則的:
? ? ? ?該原則是由羅伯特·C·馬丁于《敏捷軟件開發(fā):原則、模式和實踐》一書中給出。它規(guī)定一個類只應(yīng)該只有一個發(fā)生變化的原因。所謂職責是指類變化的原因,如果一個類有多于一個的動機被改變,那么這個類就具有多于一個的職責,而單一職責原則就是指一個類或者模塊應(yīng)該只有一個改變的原因。
? ? ? ?這樣解釋單一職責原則恐怕比較難以理解,我們可先通過實現(xiàn)一個圖片加載器,并且將圖片緩存起來的需求的例子來理解一下單一職責原則。
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.util.LruCache;
import android.widget.ImageView;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import retrofit2.http.Url;
/**
* 圖片加載類
*/
public class ImageLoader {
LruCache<String, Bitmap> mImageCache;
//線程池,線程數(shù)量為CPU的數(shù)量
ExecutorService mExecutorService= Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
public ImageLoader(){
initImageCache();
}
private void initImageCache()
{
//計算可以使用的最大內(nèi)存
final int maxMemory= (int) (Runtime.getRuntime().maxMemory()/1024);
//取可用內(nèi)存的1/4
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;
}
};
}
/**
* 將下載的Bitmap對象顯示在Imageview上
* @param url
* @param imageView
*/
public void displayBitmap(final String url, final ImageView imageView){
imageView.setTag(url);
mExecutorService.submit(new Runnable() {
@Override
public void run() {
Bitmap bitmap=downBitmap(url);
if(bitmap==null)
{
return;
}
if(imageView.getTag().equals(url))
{
imageView.setImageBitmap(bitmap);
}
mImageCache.put(url,bitmap);
}
});
}
/**
* 通過URL下載圖片,并返回Bitmap
* @param imageUrl
* @return
*/
public Bitmap downBitmap(String imageUrl)
{
Bitmap bitmap=null;
try{
URL url=new URL(imageUrl);
final HttpURLConnection connection= (HttpURLConnection) url.openConnection();
bitmap= BitmapFactory.decodeStream(connection.getInputStream());
connection.disconnect();
}catch (Exception e)
{
e.printStackTrace();
}
return bitmap;
}
}
? ? ? ?在這個類中我們實現(xiàn)了加載圖片、設(shè)置緩存,下載圖片三個基本功能。如此以來我們就實現(xiàn)了上文提出的需求。然而這樣的代碼僅僅適用于我們學習使用,在真實的正產(chǎn)環(huán)境當中由于需求會變的比較復雜,并且對可讀性,擴展性、后期維護都會有這較高的要求,如果這樣實現(xiàn)該功能,這個類會變得越來越大,代碼也越來越復雜,圖片加載系統(tǒng)也會越來越弱。這樣寫出的功能毫無設(shè)計可言,更不要說擴展性、靈活性了。所謂的單一職責原則,簡單的來說就是一個類負責一個功能。我們在此原則的基礎(chǔ)上對代碼進行拆分重構(gòu)。
ImageLoader類負責圖片加載功能,重構(gòu)后代碼如下:
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.util.LruCache;
import android.widget.ImageView;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import retrofit2.http.Url;
/**
* 圖片加載類
*/
public class ImageLoader {
ImageCache mImageCache=new ImageCache();
//線程池,線程數(shù)量為CPU的數(shù)量
ExecutorService mExecutorService= Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
/**
* 將下載的Bitmap對象顯示在Imageview上
* @param url
* @param imageView
*/
public void displayBitmap(final String url, final ImageView imageView){
imageView.setTag(url);
mExecutorService.submit(new Runnable() {
@Override
public void run() {
Bitmap bitmap=downBitmap(url);
if(bitmap==null)
{
return;
}
if(imageView.getTag().equals(url))
{
imageView.setImageBitmap(bitmap);
}
mImageCache.put(url,bitmap);
}
});
}
/**
* 通過URL下載圖片,并返回Bitmap
* @param imageUrl
* @return
*/
public Bitmap downBitmap(String imageUrl)
{
Bitmap bitmap=null;
try{
URL url=new URL(imageUrl);
final HttpURLConnection connection= (HttpURLConnection) url.openConnection();
bitmap= BitmapFactory.decodeStream(connection.getInputStream());
connection.disconnect();
}catch (Exception e)
{
e.printStackTrace();
}
return bitmap;
}
}
ImageCache類負責圖片緩存功能代碼如下:
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.util.LruCache;
import android.widget.ImageView;
import java.net.URL;
/**
* 圖片加載類
*/
public class ImageCache {
LruCache<String, Bitmap> mImageCache;
public ImageCache(){
initImageCache();
}
private void initImageCache()
{
//計算可以使用的最大內(nèi)存
final int maxMemory= (int) (Runtime.getRuntime().maxMemory()/1024);
//取可用內(nèi)存的1/4
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只負責圖片加載的邏輯,新創(chuàng)建一個類ImageCache只負責處理圖片緩存的邏輯,這樣ImageLoader的代碼量減少了,職責相對也變得更清晰了;當與緩存相關(guān)的邏輯需要修改時,圖片加載的邏輯不需要改變,而圖片加載邏輯需要改變時,也不會影響圖片緩存的邏輯。
? ? ? ?單一職責原則主要在于“單一”兩個字,如何劃分一個類,或者一個函數(shù),每個人根據(jù)自己的經(jīng)驗和業(yè)務(wù)邏輯都有自己不同的看法。但他也有一些基本規(guī)則的,如兩個完全不一樣的功能不應(yīng)該放在同一個類中。一個類中應(yīng)該是一組相關(guān)性較強的函數(shù)或者數(shù)據(jù)的封裝。我們要經(jīng)常審視自己的代碼,根據(jù)需要對類進行相應(yīng)的拆分。單一職責原則是優(yōu)化代碼需要邁出的第一步。
參考文獻:《Android源碼設(shè)計模式解析與實戰(zhàn)》 ----- 何紅輝 關(guān)愛民 著