設計模式:橋接(Bridge)模式
一、前言
寫到這里,基本上就是對前面幾種模式的擴展和區別了,可以看到我們前面的幾種模式,很多時候都出現了重疊,這里要分清一個概念,模式並不是完全隔離和獨立的,有的模式內部其實用到了其他模式的技術,但是又有自己的創新點,如果一味地認為每個模式都是獨一無二,與其他模式完全區別的,這是一種誤區,因此,這里又看到了基礎知識的重要性。從不同的角度都有各自的共同性,比如從人的角度,每個人都是不同的,可若是從原子和分子的角度,每個人又是相同的,那到底是相同還是不同,取決於我們看問題的角度。因此我們要學會求同辨異!橋接模式是一種將類的功能層次和實現層次分離的技術,所謂類的功能層次指的是類要實現什么功能,要定義多少個函數還進行處理,在功能之中我們會用到繼承來定義新的方法同時也能使用父類的方法,這樣就構成了一個層次“父類-子類-孫類...”,這就是功能層次,與之對應的就是實現層次了,其實也很好理解,如果我們事先確定了完成一件事情的最基本的子功能,那么我們定義這些子功能為接口或者抽象類,然后使用實現類來進行實現,這樣一個抽象類,多個實現類,(抽象類——>(實現類1,實現類2,實現類...))這樣的結構就是實現層次,可以看到高度一直為2,而功能層次高度為N(N為繼承的層次)。那么可不可以將這兩者分離呢,一方面我們知道一個類的基礎子功能並且能夠使用到這些子功能的實現,另一方面我們可以在這些子功能的基礎上定義出我們自己需要的功能(功能層次),如果可以的話,基本的元素就相當於空氣、水分等元素,而我們需要的功能就是將這些東西組成一種種不同的物質。這里就用到了委托,或者說是組合。實現了功能層次和實現層次分離的結構,我們稱之為橋接模式。
二、代碼實現
如上圖所示,只有DisplayImpl是抽象類,其他都是具體類,其實DisplayImpl也可以改成接口,這在原理和理念上都是一致的。在實現層次,定義了三個rawXX元素,然后對這些元素進行實現(StringDisplayImpl),這樣就保證了可擴展性,我們可以實現很多這樣的類,但是高度一直都不變,是一個平行關系。對於功能層次,主要是對實現類中的元素進行操作,同樣的使用方法對其進行簡單的封裝,便於子類的繼承和使用,因為我們定義的displayImpl是私有的,這種組合或者說委托關系,我們在builder模式中肯定很熟悉,這里要說一些區別,首先是思想上的區別,采用橋接模式,就是要將功能層次和實現層次剝離的,因此功能層次上必須有繼承,這樣才有意義,另外,對於元素的組織上,builder是定義了一個操作,這個操作有順序的對元素進行處理,無論實現層次上實現了多少個類,都要按照這個順序來處理,而橋接模式,我們可以定義新的操作,可以靈活地使用元素,可以隨意的增加新的功能,定義新的順序,這是一個很大的不同;另外在於Main對類的使用上,對於builder模式,我們可能最后使用對應於實現層次上的一些方法來得到結果,而在橋接模式,我們本來就是面向接口(抽象)編程,因此代碼中只是使用實現層次中的實現類new一個對象然后就可以使用了,沒有這種復雜的關聯關系。同時關於實現層次的實現類,為了很好的創造對象,我們可能使用抽象工廠模式來創造對象,需要根據實際情況來取舍。理解了這一點,我們來看代碼。
DisplayImpl類:雖然是實現層次,但卻是抽象的。
1 package zyr.dp.bridge; 2 3 public abstract class DisplayImpl { 4 public abstract void rawOpen(); 5 public abstract void rawPrint(); 6 public abstract void rawClose(); 7 }
StringDisplayImpl類:
1 package zyr.dp.bridge; 2 3 public class StringDisplayImpl extends DisplayImpl { 4 5 String name; 6 public StringDisplayImpl(String name){ 7 this.name=name; 8 } 9 10 public void rawOpen() { 11 printline(); 12 } 13 14 public void rawPrint() { 15 System.out.println("|||||"+name+"|||||"); 16 } 17 18 public void rawClose() { 19 printline(); 20 } 21 private void printline(){ 22 System.out.println("================"); 23 } 24 25 }
Display 類:
1 package zyr.dp.bridge; 2 3 public class Display { 4 private DisplayImpl displayImpl ; 5 public Display(DisplayImpl displayImpl){ 6 this.displayImpl=displayImpl; 7 } 8 public void open(){ 9 displayImpl.rawOpen(); 10 } 11 public void print(){ 12 displayImpl.rawPrint(); 13 } 14 public void close(){ 15 displayImpl.rawClose(); 16 } 17 public final void display(){ 18 open(); 19 print(); 20 close(); 21 } 22 23 }
CountDisplay類:
1 package zyr.dp.bridge; 2 3 public class CountDisplay extends Display { 4 5 public CountDisplay(DisplayImpl displayImpl) { 6 super(displayImpl); 7 } 8 public final void mutilDisplay(){ 9 open(); 10 for(int i=0;i<5;i++){ 11 print(); 12 } 13 close(); 14 } 15 16 }
Main類:
package zyr.dp.bridge; public class Main { public static void main(String[] args) { Display display = new Display(new StringDisplayImpl("朱彥榮")); display.display(); CountDisplay cd = new CountDisplay(new StringDisplayImpl("李山秀")); cd.display(); cd.mutilDisplay(); } }
結果:
三、總結
從上面我們可以看到這種方式的實現的好處了,首先如果我們想使用這些元素做其他的事情,我們只需要繼承功能層次的類即可,如果我們想增加的新元素,我們只需要修改實現層次的上下兩層的方法,然后就可以使用了,這樣思路非常清晰,將功能和組成功能的子功能的實現隔離開來,可以隨意的組合,便於組件化編程,比如我們將實現層次作為組件,我們只需要使用委托(組合)將我們想要實現的功能托付給實現層次來完成就好了,大大的提高了可重用性。那么到底什么是橋接呢,在哪里體現的?我想大家都知道了,那就是在委托的地方(private DisplayImpl displayImpl;)體現了,這就是橋,一座溝通功能層次和實現層次的橋。由此我們也看到,設計模式其實就是為了最大限度的實現代碼的可重用性,為此可謂是絞盡腦汁,實現了之后就能夠組件化,可移植,可擴展,從而高內聚低耦合,設計模式,我們已經漸漸地感受到了提取的初衷和意義。