[學習筆記]設計模式之Bridge

寫在前面

爲方便讀者,本文已添加至索引html

「魔鏡啊魔鏡,誰是這個世界上最美麗的人?」月光中,一個低沉的聲音迴盪在女王的臥室。「是美麗的白雪公主,她正和小霍比特人們幸福快樂地生活在森林之中。」魔鏡答道。「可惡!我才應該是最美的人,我要除掉你,白雪公主!」女巫開始用她的水晶球施展起詭異的妖術。設計模式

本來安寧的森林最近特別的鬧騰,動物們個個都焦躁不安。小霍比特人之一的theWoodcutter(樵夫)在去伐木的路上發現了一頭野熊的屍體。這頭龐然大物的傷口上除了血淋淋的爪痕,居然混雜有燒焦的痕跡。他急急忙忙回到住處,和小夥伴們商量對策。他們首先想弄明白的是,究竟是什麼入侵了本身的家園。框架

而這個世界的主人--時の魔導士,此刻正倚靠在木製的搖椅上,安詳地抽着菸斗。他一回想起本身設計的這個虛擬的童話世界,臉上就露出了滿意的笑容。他曾爲小霍比特人們建造了武器工坊(見Factory Method筆記),Weapon是一個抽象類,它的子類包括Sword, Dagger, Bow等等都繼承了Weapon的方法attack()。attack()能對敵人形成物理上的傷害……嗯,物理上的傷害。「彷佛這個還不太完美啊。在魔法的世界裏,武器是能夠被附魔Enchanted的。」魔導士嘟囔道,「好比,附上火焰的劍能輕易刺穿易燃的裝甲,附上寒冰的箭矢也能夠用來滅火呀。這想法有趣多了,讓我來加點新鮮的東西給孩子們吧。」ide

附魔後的武器(EnchantedWeapon)的確是能夠經過繼承Weapon來獲得,好比下圖:函數

可是若是這樣設計會有很糟糕的結果。武器種類不少,若是往後還要添加別的類型的武器,好比傳奇的武器(EpicWeapon)每一個都帶有史詩般的故事,裝飾性的武器(DecoratedWeapon)比起殺傷力更注重外觀等等。每添加一種武器分支,都會致使產生更多的子類。同時,若是咱們修改了Weapon的接口,那後續改動將很是巨大。學習

因而,時の魔導士引入了Bridge(橋接)模式,它將抽象部分與實現部分分離,從而很好地解決了上面所提到的問題。spa

要點梳理

  • 目的分類
    • 對象結構型模式
  • 範圍準則
    • 對象(該模式處理對象間的關係,這些關係在運行時刻是能夠變化的,更具動態性)
  • 主要功能
    • 將抽象部分與它的實現部分分離,使它們均可以獨立地變化
  • 適用狀況
    • 咱們不但願在抽象和它的實現部分之間有一個固定的綁定關係。例如這種狀況多是由於,在程序運行時刻實現部分應能夠被選擇或者切換
    • 類的抽象以及它的實現都應該能夠經過生成子類的方法加以擴充。這時Bridge模式使咱們能夠對不一樣的抽象接口和實現部分進行組合,並分別對它們進行擴充
    • 對一個抽象的實現部分的修改應對客戶不產生影響,即客戶的代碼沒必要從新編譯
    • 想在多個對象間共享實現(可能使用引用計數),但同時要求客戶並不知道這一點
  • 參與部分
    • Abstraction:定義抽象類的接口;維護一個指向Implementor類型對象的指針
    • RefinedAbstraction:擴充由Abstraction定義的接口
    • Implementor定義實現類的接口,該接口不必定要與Abstraction的接口徹底一致;事實上這兩個接口能夠徹底不一樣。通常來說,Implementor接口僅提供基本操做,而Abstraction定義了基於這些基本操做的較高層次的操做。
    • ConcreteImplementor:實現Implementor接口並定義它的具體實現。
  • 協做過程
    • AbstractionClient的請求轉發給它的Implementor對象
  • UML圖

示例分析 - 元素附魔武器誕生

利用橋接模式,咱們將各種武器抽象成Weapon類,它提供一個attack()的接口函數。對於武器的使用者,它只需操縱attack()便可。(發現這點和以前同樣,對吧?可是別急)請看示例:設計

1 class Weapon {
2 public:
3     Weapon();   
4     virtual void attack();
5 protected:
6     WeaponImpl* getWeaponImpl();
7 private: 8 WeaponImpl* _impl; 9 }

注意到,Weapon它維護了一個對WeaponImpl的引用,而該抽象類定義了具體武器的操做的接口:指針

1 class WeaponImpl {
2 public:
3     virtual act() = 0;
4     virtual addEffect(const char*) = 0;
5 protected:
6     WeaponImpl();
7 }

如今,咱們能夠將武器攻擊動做的具體實現放在WeaponImpl的子類中,從而成功分離出Weapon類這個抽象概念。做爲擴展,附魔武器EnchantedWeapon類以下: code

 1 class EnchantedWeapon : public Weapon {
 2 public:
 3     EnchantedWeapon(char*);
 4     virtual void attack();
 5 private:
 6     const char* _element;
 7 }
 8 
 9 EnchantedWeapon::EnchantedWeapon(char* e):_element(e) {}
10 
11 void EnchantedWeapon::attack() {
12     WeaponImpl* impl = getWeaponImpl();
13     
14     if (impl != 0) {
15         impl->addEffect(_element);
16         impl->act();
17     }
18 }

EnchantedWeapon能夠爲武器附上不一樣程度的魔法效果,而後經過調用WeaponImpl類的act操做來行動。具體的WeaponImpl類則根據自身狀況來實現act操做,劍能夠用來揮舞和刺擊,弓箭則要上滿弦,等等。咱們看這裏的SwordImpl

 1 class SwordImpl : public WeaponImpl {
 2 public:
 3     SwordImpl(int);
 4     virtual void addEffect(const char*);
 5     virtual void act();
 6 private:
 7     int _damage;
 8     char* _effect;
 9 }
10 
11 SwordImpl::SwordImpl(int d) {
12     _damage = d;
13 }
14 
15 void SwordImpl::addEffect(const char* e) {
16     if (_effect)
17     {
18         delete _effect;
19     }
20     _effect = new char[strlen(e)+1];
21     strcpy(_effect, e);
22 }
23 
24 void SwordImpl::act() {
25     if (_effect)
26     {
27         cout << "Wielding sword with " << _effect << endl;
28     }
29     else
30     {
31         cout << "Wielding sword" << endl;
32     }
33 }
SwordImpl

一樣的對於BowImpl來講,效果是在箭矢上的:

 1 class BowImpl : public WeaponImpl {
 2 public:
 3     BowImpl(int);
 4     virtual void addEffect(const char*);
 5     virtual void act();
 6 private:
 7     int _damage;
 8     char* _effect;
 9 }
10 
11 BowImpl::BowImpl(int d) {
12     _damage = d;
13 }
14 
15 void BowImpl::addEffect(const char* e) {
16     if (_effect)
17     {
18         delete _effect;
19     }
20     _effect = new char[strlen(e)+1];
21     strcpy(_effect, e);
22 }
23 
24 void BowImpl::act() {
25     if (_effect)
26     {
27         cout << "Shoot an arrow with " << _effect << endl;
28     }
29     else
30     {
31         cout << "Shoot an arrow" << endl;
32     }
33 }
BowImpl

一個簡單的UML圖來講明上面的模式:

在這套框架下,不管咱們是繼續添加EpicWeapon,仍是具體的DaggerImpl等,都很是方便。順便說下,咱們能夠用Weapon提供的getWeaponImpl方法來得到想要的武器實現。具體代碼在此就不做詳解了(能夠利用抽象工廠或者單例等對象建立型模式來作)。

特色總結

Bridge模式有如下幾個優勢:

  1. 分離接口及其實現部分。一個實現未必不變地綁定在一個接口上。抽象類的實現能夠在運行時刻進行配置,一個對象甚至能夠在運行時刻改變它的實現。將AbstractionImplementor分離有助於下降對實現部分編譯時刻的依賴性,當改變一個實現類時,並不須要從新編譯Abstraction類和它的客戶程序。爲了保證一個類庫的不一樣版本之間的二進制兼容性,必定要有這個性質。
  2. 提升可擴充性。咱們能夠獨立地對AbstractionImplementor層次結構進行擴充。
  3. 實現細節對客戶透明

須要注意的是,若是咱們僅有一個Implementor,能夠沒有必要建立一個抽象的Implementor類。這是Bridge模式的退化狀況;在AbstractionImplementor之間有一種一對一的關係。

寫在最後

森林裏的中間有一隻兇狠的魔法生物,混身散發着火焰,周圍是燒焦的樹木。它彷佛被頑強的霍比特人激怒了,咆哮了起來。僅憑普通的武器,小霍比特人們沒法打敗這隻兇獸,他們中已有好幾人身負重傷了。在危在旦夕之刻,武器工坊發出耀眼的光芒,白雪公主從中拿出了一把鑲滿冰晶的奇弓,附着了寒冰的魔法。公主拉起弓弦瞄準了火獸,「真正的戰鬥如今纔開始呢!」 ......

今天的筆記就到這裏了,歡迎你們批評指正!若是以爲能夠的話,好文推薦一下,我會很是感謝的!

相關文章
相關標籤/搜索