最新在閱讀《Android源碼設(shè)計(jì)模式解析與實(shí)戰(zhàn)》一書(shū)桌吃,我覺(jué)得寫(xiě)的很清晰,每一個(gè)知識(shí)點(diǎn)都有示例苞轿,通過(guò)示例更加容易理解茅诱。書(shū)中的知識(shí)點(diǎn)有些都接觸過(guò),有的沒(méi)有接觸過(guò)搬卒,總之瑟俭,通過(guò)閱讀這本書(shū)來(lái)梳理一下知識(shí)點(diǎn),可能有些東西在項(xiàng)目中一直在使用秀睛,然并不能籠統(tǒng)尔当,清理的說(shuō)明理解它。本文主要是記錄閱讀這本書(shū)的知識(shí)點(diǎn)和自己的一些理解蹂安。一來(lái)整理知識(shí)點(diǎn),二來(lái)方便以后查看锐帜,快速定位田盈。
單一職責(zé)原則 :優(yōu)化代碼第一步
單一職責(zé)原則(英文簡(jiǎn)稱:SRP):對(duì)于一個(gè)類而言,應(yīng)該僅有一個(gè)引起它變化的原因缴阎。這個(gè)有點(diǎn)抽象允瞧,因?yàn)樵撛瓌t的劃分界面并不是那么清晰,很多時(shí)候靠個(gè)人經(jīng)驗(yàn)來(lái)區(qū)分蛮拔。簡(jiǎn)單來(lái)說(shuō)就是一個(gè)類只負(fù)責(zé)一個(gè)功能述暂,比如加減乘除應(yīng)分別對(duì)應(yīng)一個(gè)類,而不是把四個(gè)功能放在一個(gè)類中建炫,這樣在只要有一個(gè)功能變化都需要更改這個(gè)類畦韭。
下面以實(shí)現(xiàn)一個(gè)圖片加載器(ImageLoader)來(lái)說(shuō)明:
public class ImageLoader {
//圖片內(nèi)存緩存
private LruCache<String,Bitmap> mImageCache;
//線程池,線程數(shù)量為CPU的數(shù)量
private ExecutorService mExecutorService = Executors.newFixedThreadPool(
Runtime.getRuntime().availableProcessors()
);
public ImageLoader(){
initImageLoader();
}
//初始化
private void initImageLoader() {
//計(jì)算最大的可使用內(nèi)存
final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
//取四分之一作為最大緩存內(nèi)存
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){
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);
}
});
}
}
我們一般都會(huì)這樣這樣簡(jiǎn)單的實(shí)現(xiàn)一個(gè)圖片加載工具類肛跌,這樣寫(xiě)功能雖然實(shí)現(xiàn)了艺配,但是代碼是有問(wèn)題的,代碼耦合嚴(yán)重衍慎,隨著ImageLoader功能越來(lái)越多转唉,這個(gè)類會(huì)越來(lái)越大,代碼越來(lái)越復(fù)雜稳捆。按照單一職責(zé)原則赠法,我們應(yīng)該把ImageLoader拆分一下,把各個(gè)功能獨(dú)立出來(lái)乔夯。
ImageLoader修改代碼如下:
public class ImageLoader {
//圖片緩存
ImageCache mImageCache = new ImageCache();
//線程池砖织,線程數(shù)量為CPU的數(shù)量
private ExecutorService mExecutorService = Executors.newFixedThreadPool(
Runtime.getRuntime().availableProcessors()
);
public void displayImage(final String url, final ImageView imageView){
.............
}
}
public class ImageCache {
//圖片內(nèi)存緩存
private LruCache<String,Bitmap> mImageCache;
public ImageCache(){
initImageCache();
}
//初始化
private void initImageCache() {
//計(jì)算最大的可使用內(nèi)存
final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
//取四分之一作為最大緩存內(nèi)存
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 Bitmap get(String url){
return mImageCache.get(url);
}
public void put(String url,Bitmap bitmap){
mImageCache.put(url,bitmap);
}
}
上述代碼將ImageLoader一分為二款侵,ImageLoader只負(fù)責(zé)圖片加載的邏輯,ImageCache負(fù)責(zé)緩存策略镶苞,這樣喳坠,ImageLoader的代碼變少了,職責(zé)也清晰了茂蚓,并且如果緩存策略改變了的話壕鹉,只需要修改ImageCache而不需要在修改ImageLoader了。從這個(gè)例子可以更加清晰的理解什么是單一職責(zé)原則聋涨,如何去劃分一個(gè)類的職責(zé)晾浴,每個(gè)人的看法不同,這需要根據(jù)個(gè)人的經(jīng)驗(yàn)牍白,業(yè)務(wù)邏輯而定脊凰。
開(kāi)閉原則:讓程序更穩(wěn)定,更靈活
開(kāi)閉原則(英文縮寫(xiě)為OCP): 軟件中的對(duì)象(類茂腥,函數(shù)狸涌,模塊等)對(duì)于擴(kuò)展是開(kāi)放的,但是對(duì)于修改是封閉的最岗。在軟件的生命周期內(nèi)帕胆,因?yàn)樽兓?jí)和維護(hù)的原因需要對(duì)原代碼修改時(shí)般渡,可能會(huì)將錯(cuò)誤引入已經(jīng)經(jīng)過(guò)測(cè)試的舊代碼懒豹,破壞原有的系統(tǒng)。因?yàn)楫?dāng)需求變化時(shí)驯用,我們應(yīng)盡可能的通過(guò)擴(kuò)展來(lái)實(shí)現(xiàn)脸秽,而不是修改原來(lái)的
代碼。
在實(shí)際的開(kāi)發(fā)過(guò)程中蝴乔,只通過(guò)繼承的方式來(lái)升級(jí)记餐,維護(hù)原有的系統(tǒng)只是一個(gè)理想化的狀態(tài),修改原代碼淘这,擴(kuò)展代碼往往是同時(shí)存在的剥扣。我們應(yīng)盡可能的影響原代碼。避免引入的錯(cuò)誤造成系統(tǒng)的破壞铝穷。
還是上面的那個(gè)例子钠怯,雖然通過(guò)內(nèi)存緩存解決了每次都從網(wǎng)絡(luò)下載圖片的問(wèn)題,但是Android內(nèi)存有限曙聂,并且當(dāng)應(yīng)用重啟后內(nèi)存緩存會(huì)丟失晦炊。我們需要修改一下,增加SD卡緩存,代碼如下:
public class ImageLoader {
//內(nèi)存緩存
ImageCache mImageCache = new ImageCache();
//SD卡緩存
DiskCache mDiskCache = new DiskCache();
//線程池断国,線程數(shù)量為CPU的數(shù)量
private ExecutorService mExecutorService = Executors.newFixedThreadPool(
Runtime.getRuntime().availableProcessors()
);
public void displayImage(final String url, final ImageView imageView){
//先從內(nèi)存緩存中讀取贤姆,如果沒(méi)有再?gòu)腟D卡中讀取
Bitmap bitmap = mImageCache.get(url);
if(bitmap == null){
bitmap = mDiskCache.get(url);
}
if(bitmap != null){
imageView.setImageBitmap(bitmap);
return;
}
//從網(wǎng)絡(luò)下載圖片
..........
}
}
public class DiskCache {
private final static String cacheDir = "sdcard/cache/";
/* 從緩存中獲取圖片 */
public Bitmap get(String url){
return BitmapFactory.decodeFile(cacheDir + url);
}
/* 將圖片添加到緩存中 */
public void put(String url,Bitmap bitmap){
FileOutputStream fileOutputStream = null;
try {
fileOutputStream = new FileOutputStream(cacheDir + url);
bitmap.compress(Bitmap.CompressFormat.PNG,100,fileOutputStream);
} catch (FileNotFoundException e) {
e.printStackTrace();
}finally {
if(fileOutputStream != null){
try {
fileOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
上述代碼我們?cè)黾恿薙D卡緩存,我們?cè)陲@示圖片的時(shí)候先判斷內(nèi)存緩存中是否存在如果不存在就在SD卡中找稳衬,否則再?gòu)木W(wǎng)絡(luò)下載霞捡,這樣就會(huì)有一個(gè)問(wèn)題,每增加一個(gè)新的緩存方法薄疚,我們都需要修改原來(lái)的代碼碧信,這樣可能引入Bug,而且會(huì)使原來(lái)的代碼越來(lái)越復(fù)雜,還有用戶也不能自定義緩存方法街夭。我們具體使用哪一種緩存方法是通過(guò)
if
條件判斷的,條件太多砰碴,是很容易寫(xiě)錯(cuò)的。而且代碼會(huì)越來(lái)越臃腫板丽,并且可擴(kuò)展性差呈枉。可擴(kuò)展性是框架的重要特性之一埃碱。
根據(jù)開(kāi)閉原則猖辫,當(dāng)軟件需求改變的時(shí)候,我們應(yīng)該通過(guò)擴(kuò)展的方式實(shí)現(xiàn)砚殿,而不是修改自己的代碼住册。對(duì)上述代碼進(jìn)行優(yōu)化:
public class ImageLoader {
//默認(rèn)緩存方式為內(nèi)存緩存
ImageCache mImageCache = new MemoryCache();
//線程池,線程數(shù)量為CPU的數(shù)量
private ExecutorService mExecutorService = Executors.newFixedThreadPool(
Runtime.getRuntime().availableProcessors()
);
//設(shè)置緩存方式
public void setImageCache(ImageCache cache){
mImageCache = cache;
}
public void displayImage(final String url, final ImageView imageView){
//先從緩存中讀取
Bitmap bitmap = mImageCache.get(url);
if(bitmap != null){
imageView.setImageBitmap(bitmap);
return;
}
//網(wǎng)絡(luò)下載圖片
............
}
}
public interface ImageCache {
Bitmap get(String url);
void put(String url, Bitmap bitmap);
}
通過(guò)上述代碼我們可以看出瓮具,ImageLoader增加了一個(gè)方法
setImageCache
,我們可以通過(guò)該方法設(shè)置緩存方式凡人,這就是我們常說(shuō)的依賴注入名党。當(dāng)然我們還可以自定義自己的緩存方式,只需要實(shí)現(xiàn)ImageCache
這個(gè)接口即可挠轴。然后再調(diào)用setImageCache
這個(gè)方法來(lái)設(shè)置传睹。而不需要修改ImageLoader
的代碼。這樣當(dāng)緩存需求改變的時(shí)候我們可以通過(guò)擴(kuò)展的方式來(lái)實(shí)現(xiàn)而不是修改的方法岸晦,這就是所說(shuō)的開(kāi)閉原則欧啤。同時(shí)是ImageLoader
的代碼更簡(jiǎn)潔,擴(kuò)展性和靈活性也更高启上。
里氏替換原則:構(gòu)建擴(kuò)展性更好的系統(tǒng)
里氏替換原則(英文縮寫(xiě)為L(zhǎng)SP):所有引用基類的地方都必須能夠透明的使用其子類的對(duì)象邢隧。我們知道面向?qū)ο笥腥筇匦裕悍庋b,繼承和多態(tài)冈在,里氏替換原則就是依賴?yán)^承和多態(tài)這兩大原則倒慧,里氏替換原則簡(jiǎn)單來(lái)說(shuō)就是:只要是父類引用出現(xiàn)的地方都可以替換成其子類的對(duì)象,并且不會(huì)產(chǎn)生任何的錯(cuò)誤和異常。
下面以Android中的Window和View的關(guān)系的例子來(lái)理解里氏替換原則:
//窗口類
public class Window {
public void show(View child){
child.draw();
}
}
建立視圖抽象類纫谅,測(cè)量視圖的寬高為公共代碼炫贤,繪制交給具體的子類去實(shí)現(xiàn)
public abstract class View {
public abstract void draw();
public void measure(int width,int height){
//測(cè)量視圖大小
...........
}
}
//文本類具體實(shí)現(xiàn)
public class TextView extends View {
@Override
public void draw() {
//繪制文本
...........
}
}
//按鈕類具體實(shí)現(xiàn)
public class Button extends View {
@Override
public void draw() {
//繪制按鈕
.............
}
}
上述示例中,Window依賴于View付秕,View定義了一個(gè)視圖抽象兰珍,
measure
是各個(gè)子類共享的方法,子類通過(guò)重寫(xiě)View的draw
方法來(lái)實(shí)現(xiàn)具體各自特色的內(nèi)容询吴。任何繼承View的子類都可以設(shè)置給show
方法掠河,這就是所說(shuō)的里氏替換原則,通過(guò)里式替換汰寓,就可以自定義各種各樣的口柳,千變?nèi)f化的View,然后傳遞給Window有滑,Window負(fù)責(zé)組織View跃闹,并將View顯示到屏幕上。
上面ImageLoader的例子也體現(xiàn)了里氏替換原則毛好,可以通過(guò)setImageCache
方法來(lái)設(shè)置各種各樣的緩存方式望艺,如果 setImageCache
中的cache對(duì)象不能被子類替換,那么又怎么能設(shè)置各種各樣的緩存方式呢肌访?
依賴倒置原則:讓項(xiàng)目擁有變化的能力
依賴倒置原則(英文縮寫(xiě)為DIP)指代了一種特定的解耦方式找默,使得高層次的模塊不依賴于低層次模塊的實(shí)現(xiàn)細(xì)節(jié)的目的,依賴模塊被顛倒了吼驶。這個(gè)概念更加的抽象惩激,該怎么理解呢?
依賴倒置原則有幾個(gè)關(guān)鍵的點(diǎn):
- 1.高層模塊不應(yīng)該依賴底層模塊蟹演,兩者都應(yīng)該依賴其抽象风钻。
- 2.抽象不應(yīng)該依賴細(xì)節(jié)。
- 3.細(xì)節(jié)應(yīng)該依賴抽象酒请。
在Java語(yǔ)言中骡技,抽象就是接口或者抽象類,兩者都是不能直接被實(shí)例化的羞反;細(xì)節(jié)就是實(shí)現(xiàn)類布朦,實(shí)現(xiàn)接口或者繼承抽象類而產(chǎn)生的類就是細(xì)節(jié),可以直接實(shí)例化昼窗;高層模塊就是調(diào)用端是趴;底層模塊就是實(shí)現(xiàn)端。
依賴倒置原則在Java語(yǔ)言中的表現(xiàn)就是:模塊間的依賴通過(guò)抽象發(fā)生膏秫,實(shí)現(xiàn)類直接不能直接發(fā)生依賴右遭,其依賴關(guān)系是通過(guò)接口或者抽象類產(chǎn)生的做盅。
如果類與類之間直接依賴于細(xì)節(jié),那么它們之間就有直接的耦合窘哈,當(dāng)需求變化的時(shí)候吹榴,意味著要同時(shí)修改依賴者的代碼。這就限制了系統(tǒng)的可擴(kuò)展性滚婉。
public class ImageLoader {
//直接依賴于細(xì)節(jié)
MemoryCache mImageCache = new MemoryCache();
...................
}
ImageLoader
直接依賴于MemoryCache
,MemoryCache
是一個(gè)具體的實(shí)現(xiàn)图筹,這就導(dǎo)致ImageLoader
直接依賴于細(xì)節(jié),當(dāng)MemoryCache
不能滿足而被其他緩存實(shí)現(xiàn)替換時(shí)让腹,就必須需要修改ImageLoader
的代碼远剩。
public interface ImageCache {
Bitmap get(String url);
void put(String url, Bitmap bitmap);
}
public class ImageLoader {
//依賴于抽象,并且有一個(gè)默認(rèn)的實(shí)現(xiàn)
ImageCache mImageCache = new MemoryCache();
......................
在這里我們建立了
ImageCache
抽象骇窍,并且讓ImageLoader
直接依賴于抽象而不是具體的細(xì)節(jié)瓜晤,當(dāng)需求變化時(shí),只需要實(shí)現(xiàn)ImageCache
或者繼承已有的類來(lái)完成相應(yīng)的緩存功能腹纳。然后再將具體的實(shí)現(xiàn)注入到ImageLoader
中痢掠,保證了系統(tǒng)的高擴(kuò)展性。這就是依賴倒置原則嘲恍。
接口隔離原則:讓系統(tǒng)擁有更高的靈活性
接口隔離原則(英文縮寫(xiě)為L(zhǎng)SP):客戶端不應(yīng)該依賴它不需要的接口足画。另外一種定義是:類間的依賴關(guān)系應(yīng)該建立在最小的接口上。接口隔離原則將龐大佃牛,臃腫的接口拆分成更小更具體的接口淹辞,這樣客戶端只需要知道它感興趣的方法。接口隔離的目的是解開(kāi)耦合俘侠,從而容易重構(gòu)更改和重新部署象缀。
接口隔離原則說(shuō)白了就是讓依賴的接口盡可能的小,看一下上個(gè)例子實(shí)現(xiàn)SD卡緩存的代碼:
/* 將圖片添加到緩存中 */
public void put(String url,Bitmap bitmap){
FileOutputStream fileOutputStream = null;
try {
fileOutputStream = new FileOutputStream(cacheDir + url);
bitmap.compress(Bitmap.CompressFormat.PNG,100,fileOutputStream);
} catch (FileNotFoundException e) {
e.printStackTrace();
}finally {
if(fileOutputStream != null){
try {
fileOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
我們看到這段代碼的可讀性非常的差爷速,各種
try...catch
都是非常簡(jiǎn)單的代碼攻冷,但是會(huì)嚴(yán)重影響代碼的可讀性,并且多層級(jí)的大括號(hào)很容易將代碼寫(xiě)到錯(cuò)誤的層級(jí)中遍希。那么如何解決這樣的問(wèn)題呢?Java中有一個(gè)Closeable接口里烦,該接口標(biāo)識(shí)了一個(gè)可關(guān)閉的對(duì)象凿蒜,它只有一個(gè)close方法。實(shí)現(xiàn)該接口的類有很多胁黑,F(xiàn)ileOutputStream也實(shí)現(xiàn)了該接口废封,當(dāng)程序有有多個(gè)可關(guān)閉的對(duì)象時(shí),如果都像上述代碼那樣在finally中去關(guān)閉丧蘸,就非常的麻煩了漂洋。
我們可以抽取一個(gè)工具類來(lái)專門去關(guān)閉需要關(guān)閉的對(duì)象。
public class CloseUtils {
/**
* 關(guān)閉Closeable對(duì)象
* @param closeable
*/
public static void closeQuietly(Closeable closeable){
if(null != closeable){
try {
closeable.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
使用工具類替換上述的代碼
public void put(String url,Bitmap bitmap){
FileOutputStream fileOutputStream = null;
try {
fileOutputStream = new FileOutputStream(cacheDir + url);
bitmap.compress(Bitmap.CompressFormat.PNG,100,fileOutputStream);
} catch (FileNotFoundException e) {
e.printStackTrace();
}finally {
CloseUtils.closeQuietly(fileOutputStream);
}
}
這樣代碼就簡(jiǎn)潔多了,并且CloseUtils可以用到多個(gè)可以關(guān)閉對(duì)象的地方刽漂,保證了代碼的重用性演训,它依賴于Closeable抽象而不是具體的實(shí)現(xiàn),并且建立在最小的依賴原則之上贝咙,他只需要知道對(duì)象是否可關(guān)閉样悟,其他的一概不關(guān)心,這就是接口隔離庭猩。如果現(xiàn)在只需要關(guān)閉一個(gè)對(duì)象時(shí)窟她,它卻暴露了其他的接口方法,比如OutputStream的write方法蔼水,這使得更多的細(xì)節(jié)暴露在客戶端面前震糖,還增加了使用難度。而通過(guò)Closeable接口將可關(guān)閉的對(duì)象抽象起來(lái)趴腋,這樣客戶端只需要依賴Closeable就可將其他的細(xì)節(jié)隱藏起來(lái)吊说,客戶端只需要知道這個(gè)對(duì)象可關(guān)閉即可。
在上述的ImageLoader中于样,只需要知道該緩存對(duì)象有讀取和緩存的接口即可疏叨,其他的一概不管,這樣緩存的具體實(shí)現(xiàn)是對(duì)ImageLoader隱藏的穿剖。這就是用最小化接口隔離了實(shí)現(xiàn)類的細(xì)節(jié)蚤蔓。
Robert C Martin在21世紀(jì)早期將單一職責(zé),開(kāi)閉原則糊余,里氏替換秀又,接口隔離和依賴倒置5個(gè)原則定義為SOLID原則,作為面向?qū)ο缶幊痰?個(gè)基本原則贬芥。當(dāng)這些原則在一起使用時(shí)吐辙,它使得一個(gè)軟件系統(tǒng)更清晰,更簡(jiǎn)單蘸劈,最大程度的擁抱變化昏苏。
迪米特原則:更好的可擴(kuò)展性
迪米特原則(英文縮寫(xiě)為L(zhǎng)OD):也稱為最少知識(shí)原則,一個(gè)對(duì)象應(yīng)該對(duì)其他對(duì)象有最少的理解威沫。通俗的講贤惯,一個(gè)類對(duì)自己需要耦合或者調(diào)用的類知道的最少,類的內(nèi)部如果實(shí)現(xiàn)與調(diào)用者或依賴者沒(méi)有關(guān)系棒掠。調(diào)用者或依賴者只需要知道它調(diào)用的方法即可孵构,其他的一概不知。
下面以租房的例子來(lái)理解說(shuō)明這個(gè)原則烟很。
租房大多數(shù)通過(guò)中介來(lái)租颈墅,我們假設(shè)設(shè)定的情景為:我們只要求房子的面積和租金蜡镶,其他的一概不管,中介提供給我們符合要求的房子恤筛。
public class Room {
public float area;
public float price;
public Room(float area, float price) {
this.area = area;
this.price = price;
}
}
public class Mediator {
private List<Room> mRooms = new ArrayList<>();
public Mediator(){
for (int i = 0; i < 5; i++) {
mRooms.add(new Room(14 + i,(14 + i) * 150));
}
}
public List<Room> getRooms(){
return mRooms;
}
}
public class Tenant {
private float roomArea;
private float roomPrice;
private static final float diffArea = 0.0001f;
private static final float diffPrice = 100.0001f;
public void rentRoom(Mediator mediator){
List<Room> rooms = mediator.getRooms();
for (Room room : rooms) {
if(isSuitable(room)){
System.out.print("租到房子了" + room.toString());
break;
}
}
}
private boolean isSuitable(Room room){
return Math.abs(room.price - roomPrice) < diffPrice
&& Math.abs(room.area - roomArea) < diffArea;
}
}
從上面的代碼看出官还,
Tenant
不僅依賴Mediator
,還需要頻繁的與Room
打交道叹俏,租戶類只需要通過(guò)中介找到一間符合要求的房子即可妻枕。如果把這些檢索都放在Tenant
中,就弱化了中介的作用粘驰,而且導(dǎo)致Tenant
和Room
耦合度較高屡谐。當(dāng)Room
變化的時(shí)候,Tenan
t也必須跟著變化蝌数,而且Tenant
還和Mediator
耦合愕掏,這樣關(guān)系就顯得有些混亂了。
我們需要根據(jù)迪米特原則進(jìn)行解耦顶伞。
public class Mediator {
private List<Room> mRooms = new ArrayList<>();
public Mediator(){
for (int i = 0; i < 5; i++) {
mRooms.add(new Room(14 + i,(14 + i) * 150));
}
}
public Room rentOut(float price,float area){
for (Room room : mRooms) {
if (isSuitable(price,area,room)) {
return room;
}
}
return null;
}
private boolean isSuitable(float price,float area,Room room){
return Math.abs(room.price - price) < Tenant.diffPrice
&& Math.abs(room.area - area) < Tenant.diffArea;
}
}
public class Tenant {
private float roomArea;
private float roomPrice;
public static final float diffArea = 0.0001f;
public static final float diffPrice = 100.0001f;
public void rentRoom(Mediator mediator) {
Room room = mediator.rentOut(roomPrice, roomArea);
if(null != room){
System.out.print("租到房子了" + room.toString());
}
}
}
我們將對(duì)Room的操作移到了Mediator中饵撑,這本來(lái)就是Mediator的職責(zé),根據(jù)租戶的條件檢索符合的房子唆貌,并且將房子返回給用戶即可滑潘。這樣租戶就不需要知道有關(guān)Room的細(xì)節(jié),比如和房東簽合同锨咙,房產(chǎn)證的真?zhèn)蔚扔锫薄V恍枰P(guān)注和我們相關(guān)的即可。
總結(jié)
在應(yīng)用開(kāi)發(fā)過(guò)程中酪刀,我們不僅要完成應(yīng)用的開(kāi)發(fā)工作粹舵,還需要在后續(xù)的升級(jí),維護(hù)中讓?xiě)?yīng)用系統(tǒng)能夠擁抱變化骂倘。擁抱變化意味著在滿足需求且不破壞系統(tǒng)穩(wěn)定的前提下保持高擴(kuò)展性眼滤,高內(nèi)聚,低耦合历涝,在經(jīng)歷了各個(gè)版本變更之后依然保持清晰诅需,靈活,穩(wěn)定的系統(tǒng)架構(gòu)荧库。那么遵守面向?qū)ο蟮牧笤瓌t是我們邁向的第一步诱担。