爲方便讀者,本文已添加至索引:html
「魔鏡啊魔鏡,誰是這個世界上最美麗的人?」月光中,一個低沉的聲音迴盪在女王的臥室。「是美麗的白雪公主,她正和小霍比特人們幸福快樂地生活在森林之中。」魔鏡答道。「可惡!我才應該是最美的人,我要除掉你,白雪公主!」女巫開始用她的水晶球施展起詭異的妖術。設計模式
本來安寧的森林最近特別的鬧騰,動物們個個都焦躁不安。小霍比特人之一的theWoodcutter(樵夫)在去伐木的路上發現了一頭野熊的屍體。這頭龐然大物的傷口上除了血淋淋的爪痕,居然混雜有燒焦的痕跡。他急急忙忙回到住處,和小夥伴們商量對策。他們首先想弄明白的是,究竟是什麼入侵了本身的家園。框架
而這個世界的主人--時の魔導士,此刻正倚靠在木製的搖椅上,安詳地抽着菸斗。他一回想起本身設計的這個虛擬的童話世界,臉上就露出了滿意的笑容。他曾爲小霍比特人們建造了武器工坊(見Factory Method筆記),Weapon是一個抽象類,它的子類包括Sword, Dagger, Bow等等都繼承了Weapon的方法attack()。attack()能對敵人形成物理上的傷害……嗯,物理上的傷害。「彷佛這個還不太完美啊。在魔法的世界裏,武器是能夠被附魔Enchanted的。」魔導士嘟囔道,「好比,附上火焰的劍能輕易刺穿易燃的裝甲,附上寒冰的箭矢也能夠用來滅火呀。這想法有趣多了,讓我來加點新鮮的東西給孩子們吧。」ide
附魔後的武器(EnchantedWeapon)的確是能夠經過繼承Weapon來獲得,好比下圖:函數
可是若是這樣設計會有很糟糕的結果。武器種類不少,若是往後還要添加別的類型的武器,好比傳奇的武器(EpicWeapon)每一個都帶有史詩般的故事,裝飾性的武器(DecoratedWeapon)比起殺傷力更注重外觀等等。每添加一種武器分支,都會致使產生更多的子類。同時,若是咱們修改了Weapon的接口,那後續改動將很是巨大。學習
因而,時の魔導士引入了Bridge(橋接)模式,它將抽象部分與實現部分分離,從而很好地解決了上面所提到的問題。spa
利用橋接模式,咱們將各種武器抽象成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 }
一樣的對於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 }
一個簡單的UML圖來講明上面的模式:
在這套框架下,不管咱們是繼續添加EpicWeapon,仍是具體的DaggerImpl等,都很是方便。順便說下,咱們能夠用Weapon提供的getWeaponImpl方法來得到想要的武器實現。具體代碼在此就不做詳解了(能夠利用抽象工廠或者單例等對象建立型模式來作)。
Bridge模式有如下幾個優勢:
須要注意的是,若是咱們僅有一個Implementor,能夠沒有必要建立一個抽象的Implementor類。這是Bridge模式的退化狀況;在Abstraction與Implementor之間有一種一對一的關係。
森林裏的中間有一隻兇狠的魔法生物,混身散發着火焰,周圍是燒焦的樹木。它彷佛被頑強的霍比特人激怒了,咆哮了起來。僅憑普通的武器,小霍比特人們沒法打敗這隻兇獸,他們中已有好幾人身負重傷了。在危在旦夕之刻,武器工坊發出耀眼的光芒,白雪公主從中拿出了一把鑲滿冰晶的奇弓,附着了寒冰的魔法。公主拉起弓弦瞄準了火獸,「真正的戰鬥如今纔開始呢!」 ......
今天的筆記就到這裏了,歡迎你們批評指正!若是以爲能夠的話,好文推薦一下,我會很是感謝的!