1.橋接模式介紹
橋接模式(Bridge Pattern)也稱爲橋樑模式,是結構型設計模式之一。在現實生活中大家都知道“橋樑”是連接河道兩岸的主要交通樞紐,簡而言之其作用就是連接河的兩邊,而我們的橋接模式與現實中的情況很相似,也是承擔着連接“兩邊”的作用。
2.橋接模式的定義
將抽象部分與現實部分分離,使它們都可以獨立地進行變化。
3.橋接模式的使用場景
從模式的定義中我們大致可以瞭解到,這裏“橋樑”的作用其實就是連接“抽象部分”與“實現部分”,但是事實上,任何多維度變化類或者說多個樹狀類之間的耦合都可以使用橋接模式來實現解耦。
如果一個系統需要在構件的抽象化角色和具體化角色之間增加更多的靈活性,避免在兩個層次之間建立靜態的繼承聯繫,可以通過橋接模式使它們在抽象層建立一個關聯關係。
對於那些不希望使用繼承或因爲多層次繼承導致系統類的個數急劇增加的系統,也可以考慮使用橋接模式。
一個類存在兩個獨立變化的維度,且這兩個維度都需要進行擴展。
4. 橋接模式的UML類圖
UML類圖如圖:
實現部分的抽象接口:
public interface Implementor {
/*
* 實現抽象部分的具體方法
*/
public void operatopImpl();
}
實現部分具體的實現一\二
public class ConcreteImplementorA implements Implementor {
public void operatopImpl() {
// 具體的實現類
}
}
public class ConcreteImplementorB implements Implementor {
public void operatopImpl() {
// 具體的實現類
}
}
抽象部分的實現
public abstract class Abstraction {
private Implementor mImplementor;// 聲明一個私有成員變量引用實現部分的對象
/*
* 通過實現不分對象的引用構造部分的對象
*
* @param implementor 實現部分對象的引用
*/
public Abstraction(Implementor implementor) {
this.mImplementor = implementor;
}
/*
* 通過調用實現部分具體的方法實現具體的功能
*/
public void operation() {
mImplementor.operatopImpl();
}
}
抽象部分的子類:
public class RefinedAbstraction extends Abstraction {
public RefinedAbstraction(Implementor implementor) {
super(implementor);
}
/*
* 對父類抽象部分中的方法進行擴展
*/
public void refinedOperation(){
//對Abstraction中的方法進行擴展
}
}
客戶類:
public class Main {
public static void main(String[] args) {
//客戶調用邏輯
}
角色介紹:
- Abstraction:抽象部分。
該類保持一個對實現部分對象的引用,抽象部分中的方法需要調用實現部分的對象來實現,該類一般爲抽象類。 - RefinedAbstraction:優化的抽象部分。
抽象部分的具體實現,該類一般是對抽象部分的方法進行完善和擴展。 - Implementor:實現部分。
可以爲接口或抽象類,其方法不一定要與抽象部分中的一致,一般情況下是由實現部分提供基本的操作,而抽象部分定義的則是基於實現部分這些基本操作的業務方法。 - ConcreteImplementorA/ConcreteImplementorB:實現部分的具體實現。
完善實現部分中方法定義的具體邏輯。 - Client:客戶類,客戶端程序。
5.橋接模式的簡單實現
現實生活中有很多橋接模式應用的影子,比如開關與具體的電器,開關的類型有多種,而電器也是各式各樣,這兩者是獨立變化的且又有耦合。還有程序員天天面對的顯示屏,對於顯示屏來說它的尺寸與生產廠商之間也是一種二維關係,具體的尺寸與具體的廠商獨立變化,而更貼近生活的例子就是我們在和咖啡時,咖啡一般分爲4種。大杯加糖、大杯不加糖、大杯不加糖、小杯加糖、小杯不加糖,對一杯咖啡來說這說4中實質就兩種變化,一是大杯小杯,二是加糖不加糖,不管怎樣,我們都先來定義一個咖啡類。
public abstract class Coffee {
protected CoffeeAdditives impl;
public Coffee(CoffeeAdditives impl) {
this.impl = impl;
}
/*
* 咖啡具體是什麼樣的由子類決定
*/
public abstract void makeCoffee();
}
Coffee類中保持了對CoffeeAddivities的引用,一便調用具體的實現。同樣地,咖啡還分大杯小杯,定義兩個子類繼承與Coffee。
public class LargeCoffee extends Coffee{
public LargeCoffee(CoffeeAdditives impl) {
super(impl);
}
public void makeCoffee() {
System.out.println("大杯的"+impl.addSomeString()+"咖啡");
}
}
public class SmallCoffee extends Coffee{
public SmallCoffee(CoffeeAdditives impl) {
super(impl);
}
public void makeCoffee() {
System.out.println("小杯的"+impl.addSomeString()+"咖啡");
}
}
而對於加進咖啡中的糖,當然也可以選擇不加,我們也用一個抽象類定義:
public abstract class CoffeeAdditives {
/*
* 具體要往咖啡裏添加什麼也是由子類實現
*
* @return 具體添加的東西
*/
public abstract String addSomeString();
}
注意i,這裏的CoffeeAdditives其實就是對英語上面我們UML類圖中的實現部分,而Coffee則對應於抽象部分,模式定義中所謂的“抽象”與"實現"實質上對應的是兩個獨立變化的維度,因此,上文中我們也曾說過,任何多維度變化類或者說多個樹狀類之間耦合都可以使用橋接模式來實現解耦。在本例中,我們的Coffee類雖是一個抽象類,但是並非所謂的“抽象部分”,而CoffeeAddivitives類也並非一定就是“實現部分”,兩者各自爲一維度,獨立變化僅此而已,所謂的”抽象與實現分離“更偏向於我們實際的程序開發,兩者並不一定掛鉤,這裏其實就可以看到橋接模式的應用型其實很廣泛,並不侷限與程序設計。
CoffeeAdditives對應的兩個子類:加糖與不加糖
public class Sugar extends CoffeeAdditives{
public String addSomeString() {
return "加糖";
}
}
public class Ordinary extends CoffeeAdditives{
public String addSomeString() {
return "不加糖";
}
}
不加糖我們以原味表示,最後來看客戶端,將兩者進行整合。
public class Main {
public static void main(String[] args) {
//原汁原味
Ordinary implOrdinary =new Ordinary();
//準備加糖
Sugar implSugar=new Sugar();
//大杯咖啡 原味
LargeCoffee largeCoffeeOrdinary=new LargeCoffee(implOrdinary);
largeCoffeeOrdinary.makeCoffee();
//小杯咖啡 原味
SmallCoffee smallCoffeeOrdinary=new SmallCoffee(implOrdinary);
smallCoffeeOrdinary.makeCoffee();
//大杯咖啡 加糖
LargeCoffee largeCoffeeSugar=new LargeCoffee(implSugar);
largeCoffeeSugar.makeCoffee();
//小杯咖啡 加糖
SmallCoffee smallCoffeeSugar=new SmallCoffee(implSugar);
smallCoffeeSugar.makeCoffee();
}
}
輸出:
大杯的不加糖咖啡
小杯的不加糖咖啡
大杯的加糖咖啡
小杯的加糖咖啡
從本例我們可以看到,不管是Coffee變化了還是CoffeeAdditives變化了,其相對於對方而言都是獨立的沒有什麼過多的交集,兩者之間唯一的聯繫就是Coffee中保持的對CoffeeAdditives的引用,此乃兩者之紐帶,這就是橋接模式。
6.總結
橋接模式可以應用到許多開發中,但是它應用的卻不多,一個很重要的原因是對於抽象與實現的分離的被我,是不是需要分離、如何分離?對設計者來說要有一個恰到好處的分寸。不管怎麼說,橋接模式的有點我們無容置疑,分離抽象與實現、靈活的擴展以及對呵護來說透明的實現等。但是使用橋接模式也有一個不明顯的缺點,就是不容易設計,對開發者來說要有一定的經驗要求。因此,對橋接模式應用來說,理解很簡單,設計卻不容易。