4.2 美女何其多,觀點各不同
我們舉例來說明接口隔離原則到底對我們提出了什么要求。現在男生對小姑娘的稱呼,使用頻率最高的應該是“美女”了吧,你在大街上叫一聲:“嗨,美女!”估計10個有8個回頭,其中包括那位著名的如花。美女的標準各不相同,首先就需要定義一下什么是美女:首先要面貌好看,其次是身材要窈窕,然后要有氣質,當然了,這三者各人的排列順序不一樣,總之要成為一名美女就必須具備:面貌、身材和氣質,我們用類圖體現一下星探(當然,你也可以把自己想象成星探)找美女的過程,如圖4-1所示。

圖4-1 星探尋找美女的類圖
定義了一個IPettyGirl接口,聲明所有的美女都應該有goodLooking、niceFigure和great-Temperament,然后又定義了一個抽象類AbstractSearcher,其作用就是搜索美女并顯示其信息,只要美女都按照這個規范定義,Searcher(星探)就輕松多了,美女類的實現如代碼清單4-1所示。
代碼清單4-1 美女類
public?interface?IPettyGirl?{
?????//要有姣好的面孔
?????public?void?goodLooking();
?????//要有好身材
?????public?void?niceFigure();
?????//要有氣質
?????public?void?greatTemperament();
}
美女的標準定義完畢,具體的美女實現類如代碼清單4-2所示。
代碼清單4-2 美女實現類
public?class?PettyGirl?implements?IPettyGirl?{
?????private?String?name;
?????//美女都有名字
?????public?PettyGirl(String?_name){
?????????????this.name=_name;
?????}??
?????//臉蛋漂亮
?????public?void?goodLooking()?{
?????????????System.out.println(this.name?+?"---臉蛋很漂亮!");
?????}
?????//氣質要好
?????public?void?greatTemperament()?{
?????????????System.out.println(this.name?+?"---氣質非常好!");
?????}??
?????//身材要好
?????public?void?niceFigure()?{
?????????????System.out.println(this.name?+?"---身材非常棒!");
?????}
}
通過三個方法,把對美女的要求都定義出來了,按照這個標準,如花姑娘被排除在美女標準之外了。有美女,就有搜索美女的星探,其具體實現如代碼清單4-3所示。
代碼清單4-3 星探抽象類源代碼
public?abstract?class?AbstractSearcher?{
?????protected?IPettyGirl?pettyGirl;
?????public?AbstractSearcher(IPettyGirl?_pettyGirl){
?????????????this.pettyGirl?=?_pettyGirl;
?????}
?????//搜索美女,列出美女信息
?????public?abstract?void?show();
}
星探的實現類就比較簡單了,其源代碼如代碼清單4-4所示。
代碼清單4-4 星探類
public?class?Searcher?extends?AbstractSearcher{
?????public?Searcher(IPettyGirl?_pettyGirl){
?????????????super(_pettyGirl);
?????}
?????//展示美女的信息
?????public?void?show(){
?????????????System.out.println("--------美女的信息如下:---------------");
?????????????//展示面容
?????????????super.pettyGirl.goodLooking();
?????????????//展示身材
?????????????super.pettyGirl.niceFigure();
?????????????//展示氣質
?????????????super.pettyGirl.greatTemperament();
?????}
}
場景中的兩個角色美女和星探都已經出現了,需要寫一個場景類來串聯起各個角色,場景類的實現如代碼清單4-5所示。
代碼清單4-5 場景類
public?class?Client?{
?????//搜索并展示美女信息
?????public?static?void?main(String[]?args)?{
?????????????//定義一個美女
?????????????IPettyGirl?yanYan?=?new?PettyGirl("嫣嫣");
?????????????AbstractSearcher?searcher?=?new?Searcher(yanYan);
?????????????searcher.show();
?????}
}
星探搜索美女的運行結果如下所示:
--------美女的信息如下:---------------
嫣嫣---臉蛋很漂亮!
嫣嫣---身材非常棒!
嫣嫣---氣質非常好!
星探尋找美女的程序開發完畢了,運行結果也正確。我們回頭來想想這個程序有沒有問題,思考一下IPettyGirl這個接口,這個接口是否做到了最優化設計?答案是沒有,還可以對接口進行優化。
我們的審美觀點都在改變,美女的定義也在變化。唐朝的楊貴妃如果活在現在這個年代非羞愧而死不可,為什么?胖呀!但是胖并不影響她入選中國四大美女,說明當時的審美觀與現在是有差異的。當然,隨著時代的發展我們的審美觀也在變化,當你發現有一個女孩,臉蛋不怎么樣,身材也一般般,但是氣質非常好,我相信大部分人都會把這樣的女孩叫美女,審美素質提升了,就產生了氣質型美女,但是我們的接口卻定義了美女必須是三者都具備,按照這個標準,氣質型美女就不能算美女,那怎么辦?可能你要說了,我重新擴展一個美女類,只實現greatTemperament方法,其他兩個方法置空,什么都不寫,不就可以了嗎?聰明,但是行不通!為什么呢?星探AbstractSearcher依賴的是IPettyGirl接口,它有三個方法,你只實現了兩個方法,星探的方法是不是要修改?我們上面的程序打印出來的信息少了兩條,還讓星探怎么去辨別是不是美女呢?
分析到這里,我們發現接口IPettyGirl的設計是有缺陷的,過于龐大了,容納了一些可變的因素,根據接口隔離原則,星探AbstractSearcher應該依賴于具有部分特質的女孩子,而我們卻把這些特質都封裝了起來,放到了一個接口中,封裝過度了!問題找到了,我們重新設計一下類圖,修改后的類圖如圖4-2所示。
把原IPettyGirl接口拆分為兩個接口,一種是外形美的美女IGoodBodyGirl,這類美女的特點就是臉蛋和身材極棒,超一流,但是沒有審美素質,比如隨地吐痰,文化程度比較低;另外一種是氣質美的美女IGreatTemperamentGirl,談吐和修養都非常高。我們把一個比較臃腫的接口拆分成了兩個專門的接口,靈活性提高了,可維護性也增加了,不管以后是要外形美的美女還是氣質美的美女都可以輕松地通過PettyGirl定義。兩種類型的美女定義如代碼清單4-6所示。

圖4-2 修改后的星探尋找美女類圖
代碼清單4-6 兩種類型的美女定義
public?interface?IGoodBodyGirl?{
?????//要有姣好的面孔
?????public?void?goodLooking();
?????//要有好身材
?????public?void?niceFigure();
}
public?interface?IGreatTemperamentGirl?{
?????//要有氣質
?????public?void?greatTemperament();
}
按照臉蛋、身材、氣質都具備才算美女,實現類實現兩個接口,如代碼清單4-7所示。
代碼清單4-7 最標準的美女
public?class?PettyGirl?implements?IGoodBodyGirl,IGreatTemperamentGirl?{
?????private?String?name;
?????//美女都有名字
?????public?PettyGirl(String?_name){
?????????????this.name=_name;
?????}
?????//臉蛋漂亮
?????public?void?goodLooking()?{
?????????????System.out.println(this.name?+?"---臉蛋很漂亮!");
?????}
?????//氣質要好
?????public?void?greatTemperament()?{
?????????????System.out.println(this.name?+?"---氣質非常好!");
?????}
?????//身材要好
?????public?void?niceFigure()?{
?????????????System.out.println(this.name?+?"---身材非常棒!");
?????}
}
通過這樣的重構以后,不管以后是要氣質美女還是要外形美女,都可以保持接口的穩定。當然,你可能要說了,以后可能審美觀點再發生改變,只有臉蛋好看就是美女,那這個IGoodBody接口還是要修改的呀,確實是,但是設計是有限度的,不能無限地考慮未來的變更情況,否則就會陷入設計的泥潭中而不能自拔。
以上把一個臃腫的接口變更為兩個獨立的接口所依賴的原則就是接口隔離原則,讓星探AbstractSearcher依賴兩個專用的接口比依賴一個綜合的接口要靈活。接口是我們設計時對外提供的契約,通過分散定義多個接口,可以預防未來變更的擴散,提高系統的靈活性和可維護性。
- 前言
- 第一部分 大旗不揮,誰敢沖鋒——6大設計原則全新解讀
- 第1章 單一職責原則
- 1.2 絕殺技,打破你的傳統思維
- 1.3 我單純,所以我快樂
- 1.4 最佳實踐
- 第2章 里氏替換原則
- 2.2 糾紛不斷,規則壓制
- 2.3 最佳實踐
- 第3章 依賴倒置原則
- 3.2 言而無信,你太需要契約
- 3.3 依賴的三種寫法
- 3.4 最佳實踐
- 第4章 接口隔離原則
- 4.2 美女何其多,觀點各不同
- 4.3 保證接口的純潔性
- 4.4 最佳實踐
- 第5章 迪米特法則
- 5.2 我的知識你知道得越少越好
- 5.3 最佳實踐
- 第6章 開閉原則
- 6.2 開閉原則的廬山真面目
- 6.3 為什么要采用開閉原則
- 6.4 如何使用開閉原則
- 6.5 最佳實踐
- 第二部分 真刀實槍 ——23種設計模式完美演繹
- 第7章 單例模式
- 7.2 單例模式的定義
- 7.3 單例模式的應用
- 7.4 單例模式的擴展
- 7.5 最佳實踐
- 第8章 工廠方法模式
- 8.2 工廠方法模式的定義
- 8.3 工廠方法模式的應用
- 8.4 工廠方法模式的擴展
- 8.5 最佳實踐
- 第9章 抽象工廠模式
- 9.2 抽象工廠模式的定義
- 9.3 抽象工廠模式的應用
- 9.4 最佳實踐
- 第10章 模板方法模式
- 10.2 模板方法模式的定義
- 10.3 模板方法模式的應用
- 10.4 模板方法模式的擴展
- 10.5 最佳實踐
- 第11章 建造者模式
- 11.2 建造者模式的定義
- 11.3 建造者模式的應用
- 11.4 建造者模式的擴展
- 11.5 最佳實踐
- 第12章 代理模式
- 12.2 代理模式的定義
- 12.3 代理模式的應用
- 12.4 代理模式的擴展
- 12.5 最佳實踐
- 第13章 原型模式
- 13.2 原型模式的定義
- 13.3 原型模式的應用
- 13.4 原型模式的注意事項
- 13.5 最佳實踐
- 第14章 中介者模式
- 14.2 中介者模式的定義
- 14.3 中介者模式的應用
- 14.4 中介者模式的實際應用
- 14.5 最佳實踐
- 第15章 命令模式
- 15.2 命令模式的定義
- 15.3 命令模式的應用
- 15.4 命令模式的擴展
- 15.5 最佳實踐
- 第16章 責任鏈模式
- 16.2 責任鏈模式的定義
- 16.3 責任鏈模式的應用
- 16.4 最佳實踐
- 第17章 裝飾模式
- 17.2 裝飾模式的定義
- 17.3 裝飾模式應用
- 17.4 最佳實踐
- 第18章 策略模式
- 18.2 策略模式的定義
- 18.3 策略模式的應用
- 18.4 策略模式的擴展
- 18.5 最佳實踐
- 第19章 適配器模式
- 19.2 適配器模式的定義
- 19.3 適配器模式的應用
- 19.4 適配器模式的擴展
- 19.5 最佳實踐
- 第20章 迭代器模式
- 20.2 迭代器模式的定義
- 20.3 迭代器模式的應用
- 20.4 最佳實踐
- 第21章 組合模式
- 21.2 組合模式的定義
- 21.3 組合模式的應用
- 21.4 組合模式的擴展
- 21.5 最佳實踐
- 第22章 觀察者模式
- 22.2 觀察者模式的定義
- 22.3 觀察者模式的應用
- 22.4 觀察者模式的擴展
- 22.5 最佳實踐
- 第23章 門面模式
- 23.2 門面模式的定義
- 23.3 門面模式的應用
- 23.4 門面模式的注意事項
- 23.5 最佳實踐
- 第24章 備忘錄模式
- 24.2 備忘錄模式的定義
- 24.3 備忘錄模式的應用
- 24.4 備忘錄模式的擴展
- 24.5 最佳實踐
- 第25章 訪問者模式
- 25.2 訪問者模式的定義
- 25.3 訪問者模式的應用
- 25.4 訪問者模式的擴展
- 25.5 最佳實踐
- 第26章 狀態模式
- 26.2 狀態模式的定義
- 26.3 狀態模式的應用
- 第27章 解釋器模式
- 27.2 解釋器模式的定義
- 27.3 解釋器模式的應用
- 27.4 最佳實踐
- 第28章 享元模式
- 28.2 享元模式的定義
- 28.3 享元模式的應用
- 28.4 享元模式的擴展
- 28.5 最佳實踐
- 第29章 橋梁模式
- 29.2 橋梁模式的定義
- 29.3 橋梁模式的應用
- 29.4 最佳實踐
- 第三部分 誰的地盤誰做主 ——設計模式PK
- 第30章 創建類模式大PK
- 30.1 工廠方法模式VS建造者模式
- 30.2 抽象工廠模式VS建造者模式
- 第31章 結構類模式大PK
- 31.1 代理模式VS裝飾模式
- 31.2 裝飾模式VS適配器模式
- 第32章 行為類模式大PK
- 32.1 命令模式VS策略模式
- 32.2 策略模式VS狀態模式
- 32.3 觀察者模式VS責任鏈模式
- 第33章 跨戰區PK
- 33.1 策略模式VS橋梁模式
- 33.2 門面模式VS中介者模式
- 33.3 包裝模式群PK
- 第四部分 完美世界 ——設計模式混編
- 第34章 命令模式+責任鏈模式
- 34.2 混編小結
- 第35章 工廠方法模式+策略模式
- 35.2 混編小結
- 第36章 觀察者模式+中介者模式
- 36.2 混編小結
- 第五部分 擴展篇
- 第37章 MVC框架
- 37.2 最佳實踐
- 第38章 新模式
- 38.1 規格模式
- 38.2 對象池模式
- 38.3 雇工模式
- 38.4 黑板模式
- 38.5 空對象模式
- 附錄 23種設計模式彩圖