單一職責(zé)原則(SRP)又稱單一功能原則薪寓,為面向?qū)ο罅蠡驹瓌t之一社痛。
我們先來看一下官方是如何描述該原則的:
? ? ? ?該原則是由羅伯特·C·馬丁于《敏捷軟件開發(fā):原則改览、模式和實(shí)踐》一書中給出并淋。它規(guī)定一個類只應(yīng)該只有一個發(fā)生變化的原因刁憋。所謂職責(zé)是指類變化的原因,如果一個類有多于一個的動機(jī)被改變墓毒,那么這個類就具有多于一個的職責(zé)吓揪,而單一職責(zé)原則就是指一個類或者模塊應(yīng)該只有一個改變的原因。
? ? ? ?這樣解釋單一職責(zé)原則恐怕比較難以理解所计,我們可先通過實(shí)現(xiàn)一個圖片加載器柠辞,并且將圖片緩存起來的需求的例子來理解一下單一職責(zé)原則。
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()
{
//計(jì)算可以使用的最大內(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;
}
}
? ? ? ?在這個類中我們實(shí)現(xiàn)了加載圖片习勤、設(shè)置緩存,下載圖片三個基本功能焙格。如此以來我們就實(shí)現(xiàn)了上文提出的需求图毕。然而這樣的代碼僅僅適用于我們學(xué)習(xí)使用,在真實(shí)的正產(chǎn)環(huán)境當(dāng)中由于需求會變的比較復(fù)雜眷唉,并且對可讀性吴旋,擴(kuò)展性、后期維護(hù)都會有這較高的要求厢破,如果這樣實(shí)現(xiàn)該功能荣瑟,這個類會變得越來越大,代碼也越來越復(fù)雜摩泪,圖片加載系統(tǒng)也會越來越弱笆焰。這樣寫出的功能毫無設(shè)計(jì)可言,更不要說擴(kuò)展性见坑、靈活性了嚷掠。所謂的單一職責(zé)原則,簡單的來說就是一個類負(fù)責(zé)一個功能荞驴。我們在此原則的基礎(chǔ)上對代碼進(jìn)行拆分重構(gòu)不皆。
ImageLoader類負(fù)責(zé)圖片加載功能,重構(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類負(fù)責(zé)圖片緩存功能代碼如下:
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()
{
//計(jì)算可以使用的最大內(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只負(fù)責(zé)圖片加載的邏輯鲫骗,新創(chuàng)建一個類ImageCache只負(fù)責(zé)處理圖片緩存的邏輯犬耻,這樣ImageLoader的代碼量減少了,職責(zé)相對也變得更清晰了执泰;當(dāng)與緩存相關(guān)的邏輯需要修改時(shí)枕磁,圖片加載的邏輯不需要改變,而圖片加載邏輯需要改變時(shí)术吝,也不會影響圖片緩存的邏輯计济。
? ? ? ?單一職責(zé)原則主要在于“單一”兩個字,如何劃分一個類排苍,或者一個函數(shù)沦寂,每個人根據(jù)自己的經(jīng)驗(yàn)和業(yè)務(wù)邏輯都有自己不同的看法。但他也有一些基本規(guī)則的纪岁,如兩個完全不一樣的功能不應(yīng)該放在同一個類中凑队。一個類中應(yīng)該是一組相關(guān)性較強(qiáng)的函數(shù)或者數(shù)據(jù)的封裝则果。我們要經(jīng)常審視自己的代碼幔翰,根據(jù)需要對類進(jìn)行相應(yīng)的拆分漩氨。單一職責(zé)原則是優(yōu)化代碼需要邁出的第一步。
參考文獻(xiàn):《Android源碼設(shè)計(jì)模式解析與實(shí)戰(zhàn)》 ----- 何紅輝 關(guān)愛民 著