設計模式(Design Patterns)筆記之三:Bridge

前言:不好意思,前段時間由於各方面的原因,沒顧上寫了。這就加油補上。^_^

概念:
Bridge:將抽象部分與它的實現部分分離,使它們都可以獨立地變化。

--------------------------------------
烈日,當空;沒有一絲風,真的讓人感覺透不過氣來。想起去年夏天在沒有空調的房子裏寫代碼,^_^,真是對人性的一種考驗。AndyTao正想着,不覺笑了。午休時間也快過了,繼續寫我的代碼吧。

“Andy,過來幫我看看嘛!”一串銀鈴聲傳了過來。

“唉,美女相邀,怎能不動啊。”AndyTao心裏想着,沒敢說出口。“我說,你又怎麼了?就你事多。”

“上次技術討論會上聽你說過,如果一個抽象類或者接口有多個具體的實現類(concrete subclass)的時候,爲了不至於由於使用單純繼承進行抽象類或接口的具體實現而導致代碼混亂和可重用性不強,你說應當採用Bridge設計模式,這是怎麼一回事啊?你看我現在這個例子採用繼承不是很好嗎?”

“哦,我看看。”

public interface Draw {
public void paint();
}

public class DrawCircle implements Draw {
   public void paint(){
System.out.println("paint Circle");
……
}
……
}

public class DrawAngle implements Draw {
   public void paint(){
System.out.println("paint Angle");
……
}
……
}

“你看看,我這裏不是各幹其事,做得挺好嘛。”

“呵呵,聽我細細講來。通常,當一個抽象類或接口有多個具體實現(concrete subclass),這些concrete之間關係可能有以下兩種情況:第一種是,這多個具體實現之間恰好是並列關係,就像你的這段代碼,有兩個concrete class:畫圓和畫三角;這兩個形狀上的圖形是並列的,沒有相對概念上的重複,那麼我們只要使用繼承就可以了。……”

“別賣關子了好不好!”“……”“好啦好啦,我請你喝可樂可以吧?”

嘿嘿,奸計得逞,AndyTao繼續說道,“但是,我們要考慮到第二種情況,如果我們兩個或多個具體實現之間有概念重複,那麼需要我們把抽象共同部分和行爲共同部分各自獨立開來,原來是準備放在一個接口裏,現在需要設計兩個接口,分別放置抽象部分和行爲部分。”

“好抽象啊,我聽不懂!”

“那好,我們來舉個例子,嗯……,就拿可樂來說吧,我們喝的可樂有大杯和小杯之分,而又有加冰和不加冰之分,這樣,如果我們採用單純繼承來實現這四個具體實現(大杯加冰,大杯不加冰,小杯加冰,小杯不加冰),那麼很容易造成相互之間的概念重疊,而且代碼混亂,不容易維護。所以……”

“所以,怎麼?繼續繼續。”

“所以啊,我們就要採用Bridge模式來重新設計類的結構。如果採用Bridge模式,我們就需要定義兩個接口或抽象類,爲的是把抽象部分和行爲部分分隔開來。”

“稍等稍等,喝口水先。”“來來來,用我的吧。”“那……,真不好意思了,嘿嘿……”

“我們就用可樂作例子吧。將可樂定義爲抽象類,有一部分共同的實現代碼可以放到裏面,加冰和不加冰屬於行爲,那麼我們就把它定義成爲行爲接口。”

“然後,我們可以實現下面的抽象類。”

public abstract class Coke {
   CokeImp cokeImp;

   public void setCokeImp(CokeImp cokeImp) {
     this.cokeImp = cokeImp;
   }

   public CokeImp getCokeImp() {
return this.cokeImp;
}

   public abstract void distributeCoke();
}

public abstract class CokeImp {
   public abstract void distributeCokeImp();
}

“現在,我們就有了兩個抽象類(或接口)。上面,Coke是抽象部分,CokeImp是定義的行爲抽象類。爲了實現我們所說的四種類動態結合的功能,我們需要在具體實現類上下點功夫羅。”

“這是大可樂:”

public class BigCoke extends Coke
{
  public BigCoke() {}

  public void distributeCoke()
  {
    System.out.print("BigCoke ");
    CokeImp cokeImp = this.getCokeImp();
    cokeImp.distributeCokeImp();
  }
}

“這是小可樂:”

public class SmallCoke extends Coke
{
  public SmallCoke() {}

  public void distributeCoke()
  {
    System.out.print("SmallCoke ");
    CokeImp cokeImp = this.getCokeImp();
    cokeImp.distributeCokeImp();
  }
}

“我要加冰:”

public class IceCokeImp extends CokeImp
{
  IceCokeImp() {}

  public void distributeCokeImp()
  {
    System.out.print("Ice added");
  }
}


“不要冰了:”

public class NonIceCokeImp extends CokeImp
{
  NonIceCokeImp() {}

  public void distributeCokeImp()
  {
    System.out.print("Havn't ice");
  }
}

“這裏需要注意了,由於我們的CokeImp和Coke是一對一的關係,所以要從我們的用例中找到這個*Imp是一個比較關鍵和困難的事情。”

“好啦,現在,你想喝哪種可樂?”

“我要小杯可樂加冰!”“這個簡單,給你……”

Coke coke = new SmallCoke();
coke.setCokeImp(new IceCokeImp());
coke.distributeCoke();

“我要大杯可樂不加冰!”“Oh,Here!”

Coke coke = new BigCoke();
coke.setCokeImp(new NonIceCokeImp());
coke.distributeCoke();

“差不多Bridge模式就講完了,另外,Bridge被廣泛的應用於GUI和其它圖形圖象應用程序種,包括Java AWT。另外,Abstract Factory(抽象工廠模式)經常用來創建和設定一個Bridge,Bridge模式類似於Adapter(適配器模式)中的對象適配器模式。上面的兩個模式上次不是都對你講過了嘛。”

“哦,你一說我到想起來了,”Helen咬着手指,非常可愛的模樣。“哇,迷死人了!”AndyTao只有偷偷想的份。^_^

“不過,你還要注意了,你在設計Bridge類的時候,要注意對一個抽象的實現部分的修改應對客戶不產生影響,即客戶的代碼不必重新編譯。另外,Bridge將會有許多類要生成,這樣一種類層次結構說明你必須將一個對象分解成兩個部分,抽象部分和實現部分。總之一句話,將抽象部分與它的實現部分分離,使它們都可以獨立地變化。這就是Bridge模式的精髓所在了,還有……”

“還有什麼,跟個唐僧似的。”“還有啊,別忘了你的可樂!哈哈哈!!”

“你呀,什麼都記不住,就這在行。”

“哇,你這麼瞭解我啊。”“去死吧你……”“哈哈哈!!!”

-------------------------------------------------------------------------
Yakuu

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章