Bridge模式,又叫橋接模式,是針對同一接口進行擴展與實現操作的一種設計模式。
這種模式,與之前學過的適配器模式具有相似的地方,也有不同的地方,下面就讓我們一一解析吧。
首先,我們要了解到,為什么需要使用Bridge模式:
現在有一個抽象類/接口,這個抽象類是起到了一個規范的作用,規范一些方法。
示例是用來在控制台中打印輸出框和字符串(規范輸出)
- DisplayImpl 抽象類,規范了打印的方法
package site.wangxin520.gof.bridge; /** * 原先需要實現/繼承的類/接口 * @author wangXgnaw * */ public abstract class DisplayImpl { //打開輸出框 public abstract void rawOpen(); //在輸出框里面打印字符串 public abstract void rawPrint(); //當打印字符串結束后,關閉輸出框 public abstract void rawClose(); }
在此抽象類/當然也可以使用接口中,規定了三個抽象方法,讓子類去實現具體的邏輯。
- StringDisplayImpl類,這個類是用來實現DisplayImpl中的抽象方法邏輯的。
package site.wangxin520.gof.bridge; /** * 繼承了根類,並且重寫了/實現了根類中定義的方法 * @author wangXgnaw * */ public class StringDisplayImpl extends DisplayImpl{ private String string; private int width; /** * 構造方法,傳入需要規范/美化的字符串 * @param string 需要字符串 */ public StringDisplayImpl(String string) { this.string=string; this.width=string.length(); } /** * 實現父類的抽象方法,下同 */ @Override public void rawOpen() { System.out.print("+"); for (int i = 0; i < width; i++) { System.out.print("-"); } System.out.println("+"); } @Override public void rawPrint() { System.out.println("|"+string+"|"); } @Override public void rawClose() { System.out.print("+"); for (int i = 0; i < width; i++) { System.out.print("-"); } System.out.println("+"); System.out.println("*************************"); } }
在這個子類中,重寫了父類中規定的抽象方法。根據面向對象的程序開發原則可知:
代碼對擴展開放,但對於修改閉源。
所以,我們想要擴展功能的話,都是利用繼承父類,然后在子類里面去新建方法的這種模式,但這里就得注意了,我們剛開始是實現了抽象類/接口,而規定接口/抽象類就是為了去有不同的實現邏輯,而如果再去擴展的話,就只是針對某一邏輯進行擴展,如果去擴展其他實現邏輯的話,就只能采用再去重寫父類的抽象方法,再去繼承來擴展。
因此,我們想到的是吧抽象類或者接口的具體實現和擴展分開來以達到擴展功能不影響實現,增加實現又不影響擴展的功能,這樣就大大的簡化了我們的開發。這種思想就是橋接的思想,也就是使用了bridge模式。
橋接模式和適配器模式的區別也就在此:
- 首先是兩者的目的不同,橋接是為了分離接口的功能擴展和抽象方法的實現,而適配器模式是為了對同一實現提供不同接口。
- 其次是二者的實現方式不同,橋接是利用新接口去繼承原先的舊接口,以此來提供新的接口給新的實現類,而橋接並不是為了改變接口,而是去為原來的接口增加功能。
下面就是具體的代碼實現bridge模式:
- Display 在這個類里面,准備一個DisplayImpl抽象類的對象作為屬性(利用多態,可以不用關注具體是抽象方法的哪種實現)。
package site.wangxin520.gof.bridge; /** * 橋接用,實現功能的類 * @author wangXgnaw * */ public class Display { /** * 准備一個屬性,並且在構造Display類的時候將具體實現接口的類進行傳入 */ private DisplayImpl impl; public Display(DisplayImpl impl){ this.impl=impl; } /** * 擴展了原抽象方法的方法,這里就類似於適配器模式 */ public void open(){ impl.rawOpen(); } public void print(){ impl.rawPrint(); } public void close(){ impl.rawClose(); } /** * 擴展了display方法 */ public final void display(){ open(); print(); close(); } }
- CountDisplay,擴展父類的方法
package site.wangxin520.gof.bridge; /** * 繼承了Display類,繼續擴展方法 * @author wangXgnaw * */ public class CountDisplay extends Display{ /** * 利用構造,傳參,與父類相同 * @param impl */ public CountDisplay(DisplayImpl impl) { super(impl); } /** * 繼續擴展了父類的方法 * @param times */ public void multiDisplay(int times){ open(); for (int i = 0; i < times; i++) { print(); } close(); } }
- 測試類:
package site.wangxin520.gof.bridge; /** * 橋接模式的測試類 * @author wangXgnaw * */ public class Test { public static void main(String[] args) { //d1和d2都是使用了默認的display方法 Display d1=new Display(new StringDisplayImpl("Hello world")); d1.display(); Display d2=new CountDisplay(new StringDisplayImpl("Hello mars")); d2.display(); //d3使用的是擴展出來的multiDisplay方法,因為父類是不能找到子類的專屬方法,所以這里沒有采用多態的方式 CountDisplay d3=new CountDisplay(new StringDisplayImpl("Hello moon")); d3.display(); d3.multiDisplay(3); } }
- 結果
可見,最后d3擴展出來的multiDisplay是可以展示的。