???? 橋接模式(GOF):指將抽象部分和實現部分分開,讓它們各自隨意增加減少。而不受其它約束。

?????適用環境:

u?????? 你不希望在抽象和它的實現部分之間有一個固定的綁定關系。例如這種情況可能是因為,在程序運行時刻實現部分應可以被選擇或者切換。

u?????? 類的抽象以及它的實現都應該可以通過生成子類的方法加以擴充。這時Bridge模式使你可以對不同的抽象接口和實現部分進行組合,并分別對它們進行擴充。

u?????? 對一個抽象的實現部分的修改應對客戶不產生影響,即客戶的代碼不必重新編譯。

u?????? C++)你想對客戶完全隱藏抽象的實現部分。在C++中,類的表示在類接口中是可見的。

u?????? 有許多類要生成。這樣一種類層次結構說明你必須將一個對象分解成兩個部分。Rumbaugh 稱這種類層次結構為“嵌套的普化”(nested generalizations )。

u?????? 你想在多個對象間共享實現(可能使用引用計數),但同時要求客戶并不知道這一點。

為什么使用?
?????? 不希望抽象部分和行為有一種固定的綁定關系,而是應該可以動態聯系的。

如果一個抽象類或接口有多個具體實現(子類、concrete subclass),這些子類之間關系可能有以下兩種情況:
1. 這多個子類之間概念是并列的,如前面舉例,打樁,有兩個concrete class:方形樁和圓形樁;這兩個形狀上的樁是并列的,沒有概念上的重復。

2.這多個子類之中有內容概念上重疊.那么需要我們把抽象共同部分和行為共同部分各自獨立開來,原來是準備放在一個接口里,現在需要設計兩個接口:抽象接口和行為接口,分別放置抽象和行為.

例如,一杯咖啡為例,子類實現類為四個:中杯加奶、大杯加奶、 中杯不加奶、大杯不加奶。

但是,我們注意到:上面四個子類中有概念重疊,可從另外一個角度進行考慮,這四個類實際是兩個角色的組合:抽象 和行為,其中抽象為:中杯和大杯;行為為:加奶 不加奶(如加橙汁 加蘋果汁).

實現四個子類在抽象和行為之間發生了固定的綁定關系,如果以后動態增加加葡萄汁的行為,就必須再增加兩個類:中杯加葡萄汁和大杯加葡萄汁。顯然混亂,擴展性極差。

那我們從分離抽象和行為的角度,使用Bridge模式來實現。

如何實現?
以上面提到的咖啡 為例. 我們原來打算只設計一個接口(抽象類),使用Bridge模式后,我們需要將抽象和行為分開,加奶和不加奶屬于行為,我們將它們抽象成一個專門的行為接口.
??? 先看看抽象部分的接口代碼:

package?bridge;
public?abstract?class?Coffee{
????CoffeeImpl?coffeeImpl
=null;
????
????
public?void?setCoffeeImpl(){
????????
this.coffeeImpl=CoffeeImplSingleton.getCoffeeImpl();
????}

????
????
public?CoffeeImpl?getCoffeeImpl(){
????????
return?this.coffeeImpl;
????}

????
????
public?abstract?void??pourCoffee();
}

其中CoffeeImp 是加不加奶的行為接口,看其代碼如下
package?bridge;
public?abstract?class?CoffeeImpl{
????
public?abstract?void?pourCoffeeImpl();
}
現在我們有了兩個抽象類,下面我們分別對其進行繼承,實現concrete class
package?bridge;
//中杯Coffee
public?class?MediumCoffee??extends?Coffee{
????
????
public?MediumCoffee?(){
????????setCoffeeImpl();
????}

????
????
public?void?pourCoffee(){
????????CoffeeImpl?coffeeImp
=this.getCoffeeImpl();?
????????coffeeImpl.pourCoffeeImpl();
????}

}
package?bridge;
//大杯Coffee
public?class?SuperSizeCoffee?extends?Coffee{
????
public?SuperSizeCoffee?(){
????????setCoffeeImpl();
????}

????
????
public?void?pourCoffee(){
????????CoffeeImpl?coffeeImp
=this.getCoffeeImpl();?
????????coffeeImpl.pourCoffeeImpl();
????}

}

下面對行為CoffeeImp進行繼承:
package?bridge;
//不加牛奶
public?class?FragrantCoffeeImpl?extends?CoffeeImpl{
????
public?void?pourCoffeeImpl(){
????????System.out.println(
"沒有加牛奶的Coffee");
????}

}
package?bridge;
//加牛奶
public?class?CoffeeImplSingleton{
????
private?static?CoffeeImpl?coffeeImpl;
????
public?CoffeeImplSingleton(CoffeeImpl?coffeeImpl){
????????
this.coffeeImpl=coffeeImpl;
????}
?
????
public?static?CoffeeImpl?getCoffeeImpl(){
????????
return?coffeeImpl;
????}

}

最后實現:
package?bridge;
public?class?Bridge{
????
public?static?void?main(String[]?args){
???????
???????
//中杯加奶
???????CoffeeImplSingleton?coffeeImpl=new?CoffeeImplSingleton(new?MilkCoffeeImpl());
???????MediumCoffee?mediumCoffee?
=?new?MediumCoffee();
???????mediumCoffee.pourCoffee();
???????
???????
//大杯不加奶
???????CoffeeImplSingleton?coffeeImpl2=new?CoffeeImplSingleton(new?FragrantCoffeeImpl());
???????SuperSizeCoffee?superSizeCoffee?
=?new?SuperSizeCoffee();
???????superSizeCoffee.pourCoffee();

????}

}
運行結果:
加了牛奶的Coffee
沒有加牛奶的Coffee
Press any key to continue...

與適配器模式的區別:橋接模式與對象形式的適配器模式很相似,然而適配器的目的是要改變已有的接口,讓它們可以相容,以使沒有關系的兩個類能一起工作,而橋接模式是分離抽象化與實現化,以使兩者的接口可以不同。因此,兩模式是往兩個相反方面努力的。

參考資料:
http://www.jdon.com/designpatterns/bridge.htm(本篇的主要來源)
????????????????????
http://www.lvjiyong.com/books/DesignPatterns/20.html
???????????????????? 《Java與模式》