橋樑模式【Bridge Pattern 】
以公司生產產品爲例子。一個房地產公司,一個山寨公司,山寨公司什麼好賺就生產什麼。我們先進行這樣的設計。看類圖:
公司Crop先定義如下:
public abstract class Corp {
/*
* 是公司就應該有生產把,甭管是什麼軟件公司還是製造業公司
* 那每個公司的生產的東西都不一樣,所以由實現類來完成
*/
protected abstract void produce();
/*
* 有產品了,那肯定要銷售呀,不銷售你公司怎麼生存
*/
protected abstract void sell();
//公司是幹什麼的?賺錢的呀,不賺錢傻子才幹
public void makeMoney(){
//每個公司都是一樣,先生產
this.produce();
//然後銷售
this.sell();
}
}
山寨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("我賺錢呀...");
}
}
在Client中進行調用:
HouseCorp houseCorp =new HouseCorp();
houseCorp.makeMoney();
ClothesCorp clothesCorp = new ClothesCorp();
clothesCorp.makeMoney();
這樣子算是實現了,但是想想山寨公司什麼好賺就往哪裏發展那麼他之前的設備和員工各方面的資源又該何去何從呢?這樣的設計就顯得不合理了,那麼再進行改善。看一下改善後的類圖:
在Corp 類和 Product 類建立一個關聯關係
Product定義如下:
public abstract class Product {
//甭管是什麼產品它總要是能被生產出來
public abstract void beProducted();
//生產出來的東西,一定要銷售出去,否則虧本呀
public abstract void beSelled();
}
再看下IPod類:
public class IPod extends Product {
public void beProducted() {
System.out.println("生產出的iPod是這個樣子的...");
}
public void beSelled() {
System.out.println("生產出的iPod賣出去了...");
}
}
於是公司Crop可以定義如下:
public abstract class Corp {
//定義一個產品對象,抽象的了,不知道具體是什麼產品
private Product product;
//構造函數,由子類定義傳遞具體的產品進來
public Corp(Product product){
this.product = product;
}
//公司是幹什麼的?賺錢的呀,不賺錢傻子才幹
public void makeMoney(){
//每個公司都是一樣,先生產
this.product.beProducted();
//然後銷售
this.product.beSelled();
}
}
那麼山寨公司就可以定義如下:
public class ShanZhaiCorp extends Corp {
//產什麼產品,不知道,等被調用的才知道
public ShanZhaiCorp(Product product){
super(product);
}
//狂賺錢
public void makeMoney(){
super.makeMoney();
System.out.println("我賺錢呀...");
}
}
通過一個有參的構造函數,這樣便可以生產不同的產品了,只需在Client中傳入不同的參數便可以進行不同的生產了。
ShanZhaiCorp shanZhaiCorp = new ShanZhaiCorp(new Clothes());
shanZhaiCorp.makeMoney();
從上面的分析來看,我們主要是將Crop和Product進行擴展,而不必對整個應用進行多大的變更,這就是橋樑模式。
接下來也可以看看橋樑模式的通用類圖:
上面的案例,把Corp類以及它的兩個實現類放到了Abstraction包中, 把House以及相關的三個實現類放到了 Implementor 包中,這兩個包分別對應了橋樑模式的業務抽象角色(Abstraction) 和業務實現角色 (Implementor) 。這兩個角色大家只要記住一句話就成:業務抽象角色引用業務實現角色,或者說業務抽象角色的部分實現是由業務實現角色完成的。
總結:
(1)橋樑模式的優點就是類間解耦,我們上面已經提到,兩個角色都可以自己的擴展下去,不會相互影響,這個也符合 OCP 原則。
(2)注意橋樑模式與繼承的對比。如果對於比較明確不發生變化的,則通過繼承來完成,若不能確定是否會發生變化的,那就認爲是會發生變化,則通過橋樑模式來解決。
橋樑模式的使用場景:
● 不希望或不適用使用繼承的場景
例如繼承層次過渡、無法更細化設計顆粒等場景,需要考慮使用橋樑模式。
● 接口或抽象類不穩定的場景
明知道接口不穩定還想通過實現或繼承來實現業務需求,那是得不償失的,也是比較失敗的做法。
● 重用性要求較高的場景
設計的顆粒度越細,則被重用的可能性就越大,而採用繼承則受父類的限制,不可能出現太細的顆粒度。