第29章 橋梁模式
29.1 我有一個夢想……
我們每個人都有理想,但不要只是空想,理想是要靠今天的拼搏來實現的。今天咱們就來談談自己的理想,如希望成為一個富翁,身價過億,有兩家大公司,一家是房地產公司,另一家是服裝制造公司。這兩家公司都很賺錢,天天幫你累積財富。其實你并不關心公司的類型,你關心的是它們是不是在賺錢,賺了多少,這才是你關注的。商人嘛,唯利是圖是其本性,偷稅漏稅是方法,欺上瞞下、壓榨員工血汗是常用的手段,先用類圖表示一下這兩個公司,如圖29-1所示。

圖29-1 盈利模式的類圖
類圖很簡單,聲明了一個Corp抽象類,定義一個公司的抽象模型,公司首要是賺錢的,做義務或善舉那也是有背后利益支撐的,還是贊成這句話“天下熙熙,皆為利來;天下攘攘,皆為利往”。我們先看Corp類的源代碼,如代碼清單29-1所示。
代碼清單29-1 抽象公司
public?abstract?class?Corp?{
?????/*
??????*?如果是公司就應該有生產,不管是軟件公司還是制造業公司
??????*?每家公司生產的東西都不一樣,所以由實現類來完成
??????*/
?????protected?abstract?void??produce();
?????/*
??????*?有產品了,那肯定要銷售啊,不銷售公司怎么生存
??????*/
?????protected?abstract?void?sell();?
?????//公司是干什么的?賺錢的
?????public?void?makeMoney(){?????
?????????????//每個公司都是一樣,先生產
?????????????this.produce();
?????????????//然后銷售
?????????????this.sell();
?????}
}
怎么這是模板方法模式啊?是的,這是個引子,請繼續往下看。合適的方法存在合適的類中,這個基本上是每本Java基礎書上都會講的,但是到實際的項目中應用的時候就不是這么回事兒了。我們繼續看兩個實現類是如何實現的,先看HouseCorp類,這是最賺錢的公司,如代碼清單29-2所示。
代碼清單29-2 房地產公司
public?class?HouseCorp?extends?Corp?{
?????//房地產公司蓋房子
?????protected?void?produce()?{
?????????????System.out.println("房地產公司蓋房子...");
?????}
?????//房地產公司賣房子,自己住那可不賺錢
?????protected?void?sell()?{
?????????????System.out.println("房地產公司出售房子...");
?????}
?????//房地產公司很High了,賺錢,計算利潤
?????public?void?makeMoney(){
?????????????super.makeMoney();
?????????????System.out.println("房地產公司賺大錢了...");
?????}
}
房地產公司按照正規翻譯來說應該是realty corp,這個是比較準確的翻譯,但是我問你把房地產公司翻譯成英文,你的第一反應是什么?house corp!這是中式英語。我們再來看服裝公司,雖然不景氣,但好歹也是賺錢的,如代碼清單29-3所示。
代碼清單29-3 服裝公司
public?class?ClothesCorp?extends?Corp?{
?????//服裝公司生產的就是衣服了
?????protected?void?produce()?{
?????????????System.out.println("服裝公司生產衣服...");
?????}
?????//服裝公司賣服裝,可只賣服裝,不賣穿衣服的模特
?????protected?void?sell()?{
?????????????System.out.println("服裝公司出售衣服...");
?????}
?????//服裝公司不景氣,但怎么說也是賺錢行業
?????public?void?makeMoney(){
?????????????super.makeMoney();
?????????????System.out.println("服裝公司賺小錢...");
?????}
}
兩個公司都有了,那肯定有人會關心兩個公司的運營情況。你也要知道它是生產什么的,以及賺多少錢吧。通過場景類來進行模擬,如代碼清單29-4所示。
代碼清單29-4 場景類
public?class?Client?{
?????public?static?void?main(String[]?args)?{
?????????????System.out.println("-------房地產公司是這樣運行的-------");
?????????????//先找到我的公司
?????????????HouseCorp?houseCorp?=new?HouseCorp();
?????????????//看我怎么掙錢
?????????????houseCorp.makeMoney();
?????????????System.out.println("\n");
?????????????System.out.println("-------服裝公司是這樣運行的-------");
?????????????ClothesCorp?clothesCorp?=?new?ClothesCorp();
?????????????clothesCorp.makeMoney();
?????}
}
這段代碼很簡單,運行結果如下所示:
-------房地產公司是這樣運行的-------
房地產公司蓋房子...
房地產公司出售房子...
房地產公司賺大錢了...
-------服裝公司是這樣運行的-------
服裝公司生產衣服...
服裝公司出售衣服...
服裝公司賺小錢...
上述代碼完全可以描述我現在的公司,但是你要知道萬物都是運動的,你要用運動的眼光看問題,公司才會發展……終于有一天你覺得賺錢速度太慢,于是你上下疏通,左右打關系,終于開辟了一條賺錢的“康莊大道”:生產山寨產品!什么產品呢?即市場上什么牌子的東西火爆我生產什么牌子的東西,不管是打火機還是電腦,只要它火爆,我就生產,賺過了高峰期就換個產品,打一槍換一個牌子,不承擔售后成本、也不擔心銷路問題,我只要正品的十分之一的價格,你買不買?哈哈,賺錢啊!
企業的方向定下來了,通過調查,蘋果公司的iPod系列產品比較火爆,那咱就生產這個,把服裝廠改成iPod生產廠,看類圖的變化,如圖29-2所示。

圖29-2 服裝公司改頭換面后的類圖
好,我的企業改頭換面了,開始生產iPod產品了,看我IPodCorp類的實現,如代碼清單29-5所示。
代碼清單29-5 iPod山寨公司
public?class?IPodCorp?extends?Corp?{
?????//我開始生產iPod了
?????protected?void?produce()?{
?????????????System.out.println("我生產iPod...");
?????}
?????//山寨的iPod很暢銷,便宜嘛
?????protected?void?sell()?{
?????????????System.out.println("iPod暢銷...");
?????}
?????//狂賺錢
?????public?void?makeMoney(){
?????????????super.makeMoney();
?????????????System.out.println("我賺錢呀...");
?????}
}
服裝工廠改成了電子工廠,你這個董事長還是要去看看到底生產什么的,場景類如代碼清單29-6所示。
代碼清單29-6 場景類
public?class?Client?{
?????public?static?void?main(String[]?args)?{
?????????????System.out.println("-------房地產公司是按這樣運行的-------");
?????????????//先找到我的公司
?????????????HouseCorp?houseCorp?=new?HouseCorp();
?????????????//看我怎么掙錢
?????????????houseCorp.makeMoney();
?????????????System.out.println("\n");?????
?????????????System.out.println("-------山寨公司是按這樣運行的-------");
?????????????IPodCorp?iPodCorp?=?new?IPodCorp();
?????????????iPodCorp.makeMoney();
?????}
}
確實,只用修改了黑色字體這幾句話,服裝廠就開始變成山寨iPod生產車間,然后你就看著你的財富在積累。山寨的東西不需要特別的銷售渠道(正品到哪里我就到哪里),不需要維修成本(大不了給你換個,你還想怎么樣,過了高峰期我就改頭換面了,你找誰維修去?投訴?投訴誰呢?),不承擔廣告成本(正品在打廣告,我還需要嗎?需要嗎?),但是也有犯愁的時候,這是一個山寨工廠,要及時地生產出市場上流行的產品,轉型要快,要靈活,今天從生產iPod轉為生產MP4,明天再轉為生產上網本,這都需要靈活的變化,不要限制得太死!那問題來了,每次我的廠房,我的工人,我的設備都在,不可能每次我換個山寨產品廠子就徹底不要了。這不行,成本忒高了點,那怎么辦?
Thinking,Thinking...I got an idea!(跳跳虎語),既然產品和工廠綁得太死,那我就給你來松松,改變設計,如圖29-3所示。

圖29-3 使用快速變化的類圖
公司和產品之間建立關聯關系,可以徹底解決以后山寨公司生產產品的問題,工廠想換產品?太容易了!看程序說話,先看Product抽象類,如代碼清單29-7所示。
代碼清單29-7 抽象產品類
public?abstract?class?Product?{
?????//甭管是什么產品它總要能被生產出來
?????public?abstract?void?beProducted();
?????//生產出來的東西,一定要銷售出去,否則虧本
?????public?abstract?void?beSelled();
}
簡單!忒簡單了!House產品類如代碼清單29-8所示。
代碼清單29-8 房子
public?class?House?extends?Product?{
?????//豆腐渣就豆腐渣唄,好歹也是房子
?????public?void?beProducted()?{
?????????????System.out.println("生產出的房子是這樣的...");
?????}
?????//雖然是豆腐渣,也是能夠銷售出去的
?????public?void?beSelled()?{
?????????????System.out.println("生產出的房子賣出去了...");
?????}
}
既然是產品類,那肯定有兩種行為要存在:被生產和被銷售,否則就不能稱為產品了。我們再來看iPod產品類,如代碼清單29-9所示。
代碼清單29-9 iPod產品
public?class?IPod?extends?Product?{
?????public?void?beProducted()?{
?????????????System.out.println("生產出的iPod是這樣的...");
?????}
?????public?void?beSelled()?{
?????????????System.out.println("生產出的iPod賣出去了...");
?????}
}
產品是由公司生產出來的,我們來看公司Corp抽象類,如代碼清單29-10所示。
代碼清單29-10 抽象公司類
public?abstract?class?Corp?{
?????//定義一個抽象的產品對象,不知道具體是什么產品
?????private?Product?product;
?????//構造函數,由子類定義傳遞具體的產品進來
?????public?Corp(Product?product){
?????????????this.product?=?product;
?????}
?????//公司是干什么的?賺錢的!
?????public?void?makeMoney(){?????
?????????????//每家公司都是一樣,先生產
?????????????this.product.beProducted();
?????????????//然后銷售
?????????????this.product.beSelled();
?????}
}
這里多了個有參構造,其目的是要繼承的子類都必選重寫自己的有參構造函數,把產品類傳遞進來,再看子類HouseCorp的實現,如代碼清單29-11所示。
代碼清單29-11 房地產公司
public?class?HouseCorp?extends?Corp?{
?????//定義傳遞一個House產品進來
?????public?HouseCorp(House?house){
?????????????super(house);
?????}
?????//房地產公司很High了,賺錢,計算利潤
?????public?void?makeMoney(){
?????????????super.makeMoney();
?????????????System.out.println("房地產公司賺大錢了...");
?????}
}
理解上沒有多少難度,不多說,繼續看山寨公司的實現,如代碼清單29-12所示。
代碼清單29-12 山寨公司
public?class?ShanZhaiCorp?extends?Corp?{
??????//產什么產品,不知道,等被調用的才知道
?????public?ShanZhaiCorp(Product?product){
?????????????super(product);
?????}
?????//狂賺錢
?????public?void?makeMoney(){
?????????????super.makeMoney();
?????????????System.out.println("我賺錢呀...");
?????}
}
HouseCorp類和ShanZhaiCorp類的區別是在有參構造的參數類型上,HouseCorp類比較明確,我就是只要House類,所以直接定義傳遞進來的必須是House類, 一個類盡可能少地承擔職責,那方法也一樣,既然HouseCorp類已經非常明確地只生產House產品,那為什么不定義成House類型呢?ShanZhaiCorp就不同了,它確定不了生產什么類型。
好了,兩大對應的陣營都已經產生了。我們再看Client程序,如代碼清單29-13所示。
代碼清單29-13 場景類
public?class?Client?{
?????public?static?void?main(String[]?args)?{
?????????????House?house?=?new?House();
?????????????System.out.println("-------房地產公司是這樣運行的-------");
?????????????//先找到房地產公司
?????????????HouseCorp?houseCorp?=new?HouseCorp(house);
?????????????//看我怎么掙錢
?????????????houseCorp.makeMoney();
?????????????System.out.println("\n");?????
?????????????//山寨公司生產的產品很多,不過我只要指定產品就成了
?????????????System.out.println("-------山寨公司是這樣運行的-------");
?????????????ShanZhaiCorp?shanZhaiCorp?=?new?ShanZhaiCorp(new?IPod());
?????????????shanZhaiCorp.makeMoney();?????
?????}
}
運行結果如下所示:
-------房地產公司是這樣運行的-------
生產出的房子是這樣的...
生產出的房子賣出去了...
房地產公司賺大錢了...
-------山寨公司是這樣運行的-------
生產出的iPod是這個樣子的...
生產出的iPod賣出去了...
我賺錢呀...
突然有一天,老板良心發現了,不準備生產這種“三無”產品了,那我們程序該怎么修改呢?如果仍重操舊業,生產衣服,那該如何處理呢?很容易處理,增加一個產品類,然后稍稍修改一下場景就可以了,我們來看衣服產品類,如代碼清單29-14所示。
代碼清單29-14 服裝
public?class?Clothes?extends?Product?{
?????public?void?beProducted()?{
?????????????System.out.println("生產出的衣服是這樣的...");
?????}
?????public?void?beSelled()?{
?????????????System.out.println("生產出的衣服賣出去了...");
?????}
}
然后再稍稍修改一下場景類,如代碼清單29-15所示。
代碼清單29-15 場景類
public?class?Client?{
?????public?static?void?main(String[]?args)?{
?????????????House?house?=?new?House();
?????????????System.out.println("-------房地產公司是這樣運行的-------");
?????????????//先找到房地產公司
?????????????HouseCorp?houseCorp?=new?HouseCorp(house);
?????????????//看我怎么掙錢
?????????????houseCorp.makeMoney();
?????????????System.out.println("\n");
?????????????//山寨公司生產的產品很多,不過我只要指定產品就成了
?????????????System.out.println("-------山寨公司是這樣運行的-------");
?????????????ShanZhaiCorp?shanZhaiCorp?=?new?ShanZhaiCorp(new?Clothes());
?????????????shanZhaiCorp.makeMoney();
?????}
}
修改后的運行結果如下所示:
-------房地產公司是這樣運行的-------
生產出的房子是這樣的...
生產出的房子賣出去了...
房地產公司賺大錢了...
-------山寨公司是這樣運行的-------
生產出的衣服是這樣的...
生產出的衣服賣出去了...
我賺錢呀...
看代碼中的黑體部分,就修改了這一條語句就完成了生產產品的轉換。那我們深入思考一下,既然萬物都是運動的,我現在只有房地產公司和山寨公司,那以后我會不會增加一些其他的公司呢?或者房地產公司會不會對業務進行細化,如分為公寓房公司、別墅公司,以及商業房公司等呢?那我告訴你,會的!絕對會的!但是你發覺沒有,這種變化對我們上面的類圖來說不會做大的修改,充其量只是擴展:
● 增加公司,要么繼承Corp類,要么繼承HouseCorp或ShanZhaiCorp,不用再修改原有的類了。
● 增加產品,繼承Product類,或者繼承House類,你要把房子分為公寓房、別墅、商業用房等。
你唯一要修改的就是Client類。類都增加了,高層模塊也需要修改,也就是說Corp類和Product類都可以自由地擴展,而不會對整個應用產生太大的變更,這就是橋梁模式。
- 前言
- 第一部分 大旗不揮,誰敢沖鋒——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種設計模式彩圖