從零開始學設計模式(七)—橋接模式

小暴說發表於2018-11-01

橋接模式(Bridage Pattern)

此模式難度等級為中級,屬結構型模式,提出者為Gang Of Four

橋接(Bridge)是用於把抽象化與實現化解耦,使得二者可以獨立變化。

它通過提供抽象化和實現化之間的橋接結構,來實現二者的解耦。

意圖

將抽象部分與實現部分分離,使它們都可以獨立的變化

主要解決:在有多種可能會變化的情況下,用繼承會造成類爆炸問題,擴充套件起來不靈活。

何時使用:實現系統可能有多個角度分類,每一種角度都可能變化。

如何解決:把這種多角度分類分離出來,讓它們獨立變化,減少它們之間耦合。

關鍵程式碼:抽象類依賴實現類。

解釋

現實世界中的例子

考慮到你有一件武器具有不同的魔法,假如允許你讓不同的武器與不同的魔法混合。你會怎麼做?一為每個不同的魔法功能建立多個武器副本,二你會根據需要為武器建立單獨的魔法並設定它。橋接模式就是你的第二選擇

簡而言之

橋接模式是關於更喜歡組合而不是繼承。實現細節從一個層次結構派生到另一個具有單獨層次結構的物件

維基百科

橋接模式是軟體工程中使用的一種設計模式,旨在“將抽象與其實現分離,以便兩者可以獨立變化”

程式示例

以上面翻譯中我們現實世界中的武器例子。如下來建造武器Weapon和魔法Enchantment的組合結構。

image.png
首先編寫武器組織結構程式碼:

public interface Weapon {
  void wield();
  void swing();
  void unwield();
  Enchantment getEnchantment();
}

public class Sword implements Weapon {

  private final Enchantment enchantment;

  public Sword(Enchantment enchantment) {
    this.enchantment = enchantment;
  }

  @Override
  public void wield() {
    LOGGER.info("The sword is wielded.");
    enchantment.onActivate();
  }

  @Override
  public void swing() {
    LOGGER.info("The sword is swinged.");
    enchantment.apply();
  }

  @Override
  public void unwield() {
    LOGGER.info("The sword is unwielded.");
    enchantment.onDeactivate();
  }

  @Override
  public Enchantment getEnchantment() {
    return enchantment;
  }
}

public class Hammer implements Weapon {

  private final Enchantment enchantment;

  public Hammer(Enchantment enchantment) {
    this.enchantment = enchantment;
  }

  @Override
  public void wield() {
    LOGGER.info("The hammer is wielded.");
    enchantment.onActivate();
  }

  @Override
  public void swing() {
    LOGGER.info("The hammer is swinged.");
    enchantment.apply();
  }

  @Override
  public void unwield() {
    LOGGER.info("The hammer is unwielded.");
    enchantment.onDeactivate();
  }

  @Override
  public Enchantment getEnchantment() {
    return enchantment;
  }
}

其次編寫分離的魔法組織結構程式碼:

public interface Enchantment {
  void onActivate();
  void apply();
  void onDeactivate();
}

public class FlyingEnchantment implements Enchantment {

  @Override
  public void onActivate() {
    LOGGER.info("The item begins to glow faintly.");
  }

  @Override
  public void apply() {
    LOGGER.info("The item flies and strikes the enemies finally returning to owner`s hand.");
  }

  @Override
  public void onDeactivate() {
    LOGGER.info("The item`s glow fades.");
  }
}

public class SoulEatingEnchantment implements Enchantment {

  @Override
  public void onActivate() {
    LOGGER.info("The item spreads bloodlust.");
  }

  @Override
  public void apply() {
    LOGGER.info("The item eats the soul of enemies.");
  }

  @Override
  public void onDeactivate() {
    LOGGER.info("Bloodlust slowly disappears.");
  }
}

最後上面兩個組織層次都起作用,自動橋接:

Sword enchantedSword = new Sword(new SoulEatingEnchantment());
enchantedSword.wield();
enchantedSword.swing();
enchantedSword.unwield();
// The sword is wielded.
// The item spreads bloodlust.
// The sword is swinged.
// The item eats the soul of enemies.
// The sword is unwielded.
// Bloodlust slowly disappears.

Hammer hammer = new Hammer(new FlyingEnchantment());
hammer.wield();
hammer.swing();
hammer.unwield();
// The hammer is wielded.
// The item begins to glow faintly.
// The hammer is swinged.
// The item flies and strikes the enemies finally returning to owner`s hand.
// The hammer is unwielded.
// The item`s glow fades.

應用場景

當遇到如下情況時你應該使用橋接模式:

  • 你希望避免抽象與其實現之間的永久繫結。例如,在執行時必須選擇或切換實現時,可能會出現這種情況
  • 抽象和它們的實現都應該通過子類化來擴充套件。在這種情況下,Bridge模式允許你組合不同的抽象和實現,並獨立地擴充套件它們
  • 一個類存在兩個獨立變化的維度,且這兩個維度都需要進行擴充套件。
  • 抽象中的具體實現發生變化時不應影響客戶端;也就是說,客戶端他們的程式碼不應該被重新編譯
  • 對於那些不希望使用繼承或因為多層次繼承導致系統類的個數急劇增加的系統,橋接模式尤為適用
  • 你想在多個物件之間共享一個實現(也許使用引用計數),這個事實應該對客戶端隱藏。一個簡單的例子是Coplien的String類,其中多個物件可以共享相同的String表示

寫在最後

對於一個類存在兩個獨立變化的維度,使用橋接模式是再適合不過了。

將抽象和實現放在兩個不同的類層次中,使它們可以獨立地變化。——《Head First 設計模式》

將類的功能層次結構和實現層次結構相分離,使二者能夠獨立地變化,並在兩者之間搭建橋樑,實現橋接。—— 《圖解設計模式》

類的功能層次結構:父類具有基本功能,在子類中增加新的功能;

類的實現層次結構:父類通過宣告抽象方法來定義介面,子類通過實現具體方法來實現介面;

橋接模式中有四個角色:

抽象化角色:使用實現者角色提供的介面來定義基本功能介面。

持有實現者角色,並在功能介面中委託給它,起到搭建橋樑的作用;

注意,抽象化角色並不是指它就是一個抽象類,而是指抽象了實現。

改善後的抽象化角色:作為抽象化角色的子類,增加新的功能,也就是增加新的介面(方法);與其構成類的功能層次結構;

實現者角色:提供了用於抽象化角色的介面;它是一個抽象類或者介面。

具體的實現者角色:作為實現者角色的子類,通過實現具體方法來實現介面;與其構成類的實現層次結構。

最後,如果抽象和實現兩者做不到獨立地變化,就不算橋接模式。

下一篇文章我們將學習結構性模式中的過濾器模式(Filter Pattern)

碼字不易,各位看官如果喜歡的話,請給點個喜歡 ️,關注下我,我將努力持續不斷的為大家更新


相關文章