???? 橋接模式(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與模式》