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

寫在前面

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

Facade(外觀)模式定義了一個高層接口,它能爲子系統中的一組接口提供一個一致的界面,從而使得這一子系統更加容易使用。歡迎回到時の魔導士的魔法世界。在對戰壞女巫的魔法生物一役中(見Bridge模式筆記),白雪公主得到大逆轉勝利機會的關鍵是附魔武器的誕生。可是,普通的武器工坊(見FactoryMethod模式筆記)生產不了附魔武器,只能是經過特殊的附魔工坊得到。通過這一戰以後,你們也以爲除了武器,還須要能保護身體的護甲來抵擋傷害。所以,霍比特人們又打算創建一些護甲工坊。如此一來,用於生產戰鬥用品的系統就愈來愈多了。小霍比特人們若是須要得到一整套適合本身的戰鬥用品,就不得不分別調用每一個系統的生產方法。事實上,小霍比特人們並不關心每一個系統具體的工做細節,他們只想要獲得一件成品而已。對於他們而言,這些生產系統中那些功能強大但層次較低的接口只會使他們的任務複雜化。設計模式

爲了讓小霍比特人們的生活、戰鬥更便利,好女巫格琳達(Glinda原型請參見《魔境仙蹤》,固然,你不會忘記一點:我確定不會忠於原著)爲他們提供了一個高層接口,而且對他們屏蔽了這些生產系統類——格琳達的小屋,在森林裏面正式開業了。因而小霍比特人們只須要來到小屋中,告訴Glinda本身須要什麼,再付上一點點小酬勞,就能夠獲得想到的東西啦。架構

那這一切跟咱們今天筆記的主題有什麼關係呢?其實這正是Facade模式一個例子,咱們將在示例分析部分更加詳細地探討這個問題。首先仍是讓咱們快速地熟悉下什麼是Facade模式吧!ide

要點梳理

  • 目的分類
    • 對象結構型模式
  • 範圍準則
    • 對象(該模式處理對象間的關係,這些關係在運行時刻是能夠變化的,更具動態性)
  • 主要功能
    • 爲子系統中的一組接口提供一個一致的界面, Facade模式定義了一個高層接口,這個接口使得這一子系統更加容易使用。
  • 適用狀況
    • 當咱們要爲一個複雜子系統提供一個簡單接口時。子系統每每由於不斷演化而變得愈來愈複雜。大多數模式使用時都會產生更多更小的類。這使得子系統更具可重用性,也更容易對子系統進行定製,但這也給那些不須要定製子系統的用戶帶來一些使用上的困難。
    • 客戶程序與抽象類的實現部分之間存在着很大的依賴性。引入Facade將這個子系統與客戶以及其餘的子系統分離,能夠提升子系統的獨立性和可移植性。
    • 當咱們須要構建一個層次結構的子系統時,使用Facade模式定義子系統中每層的入口點。若是子系統之間是相互依賴的,咱們可讓它們僅經過Facade進行通信,從而簡化了它們之間的依賴關係。
  • 參與部分
    • Facade:它知道哪些子系統類負責處理請求;它將客戶的請求代理給適當的子系統對象。
    • Subsystem Classes:實現子系統的各類功能;處理由Facade對象指派的任務;不會有Facade的任何相關信息。
  • 協做過程
    • 客戶程序經過發送請求給Facade的方式與子系統通信, Facade將這些消息轉發給適當的子系統對象。儘管是子系統中的有關對象在作實際工做,但Facade模式自己也必須將它的接口轉換成子系統的接口。
    • 使用Facade的客戶程序不須要直接訪問子系統對象。
  • 結構圖

示例分析 - 格琳達的小屋

在咱們前來參觀格琳達的小屋以前,不妨先回顧一下那些生產戰鬥用品的子系統,從而能更好地理解Facade模式工做的機制。因爲在Bridge模式筆記中提到Weapon類的設計架構發生了改變,所以包括普通的武器工坊在內的設計也相應地進行了調整。學習

首先是咱們基本的Weapon類:spa

 1 class Weapon : public VisualObject {
 2 public:
 3     Weapon(int);
 4     ~Weapon() { delete _impl; }
 5     // ... other ...
 6 protected:
 7     WeaponImpl* getWeaponImpl();
 8 private:
 9     WeaponImpl* _impl;
10 }
11 
12 Weapon::Weapon(int type) {
13     switch(type)
14     {
15         case WEAPON_SWORD:
16             _impl = new SwordImpl();
17             break;
18         case WEAPON_SHIELD:
19             _impl = new ShieldImpl();
20             break;
21         case WEAPON_BOW:
22             _impl = new BowImpl();
23             break;
24          // ... other cases ...
25          default:
26             break;        
27     }
28 }
Weapon

還有調整後的WeaponFactory類以及它的子類們:設計

 1 class WeaponFactory {
 2 public:
 3     virtual Weapon* createWeapon() = 0;
 4 }
 5 
 6 class HonorOfFighter : public WeaponFactory {
 7 public:
 8     HonorOfFighter();
 9     Weapon* createWeapon() { return new Weapon(WEAPON_SWORD); }
10 }
11 
12 class BliefOfDefender : public WeaponFactory {
13 public:
14     BliefOfDefender();
15     Weapon* createWeapon() { return new Weapon(WEAPON_SHEILD); }
16 }
17 
18 class PrecisionOfHunter : public WeaponFactory {
19 public:
20     PrecisionOfHunter();
21     Weapon* createWeapon() { return new Weapon(WEAPON_BOW); }
22 }
23 
24 // ... other weapon factories ...
WeaponFactory

以及前文中提到的附魔工坊:代理

 1 #define ENCHANTED_ICE       1
 2 #define ENCHANTED_FIRE      2
 3 #define ENCHANTED_SHOCK  3
 4 
 5 class EnchantedWeaponFactory {
 6 public:    
 7     Weapon* createEnchantedWeapon(int, int);
 8     // ... other ...
 9 }
10 
11 EnchantedWeaponFactory::createEnchantedWeapon(int element, int type) {
12     return new EnchantedWeapon(element, type);
13 }
EnchantedWeaponFactory

暫時尚未建成的護甲工坊:code

1 class ArmorFactory : public VisualObject {
2 public:
3     virtual Armor* createArmor() = 0;
4 }
ArmorFactory

好啦,該去參觀參觀格琳達的小屋HouseOfGlinda了:htm

 1 #define NOTHING    0
 2 
 3 class HouseOfGlinda {
 4 public:
 5     VisualObject* onSale(int, int);   // a simple interface.
 6     
 7     // ... It's a Singleton ...
 8     static HouseOfGlinda* getInstance() {
 9         if (_instance == 0) {
10             _instance = new HouseOfGlinda();
11         }
12         
13         return _instance;
14     }
15     
16 protected:
17     Weapon* getWeapon(int);
18     Weapon* getEnchantedWeapon(int, int);
19   // ... Armor will be comming soon ...
20 private:
21     HouseOfGlinda();
22     static HouseOfGlinda* _instance;
23 }
24 
25 VisualObject* HouseOfGlinda::onSale(int type, int info) {
26     if (WEAPON_SWORD == type ||
27         WEAPON_SHIELD == type ||
28         WEAPON_BOW == type
29         // ... other weapon ...
30       ) {
31         
32         if (NOTHING == info) {
33             return getWeapon(type);
34         }
35         else {
36             return getEnchantedWeapon(type, info);
37         }
38     }
39     // else for armor ...
40 }
41 
42 Weapon* HouseOfGlinda::getWeapon(int type) {
43     WeaponFacotry* factory = 0;
44     Weapon* weapon = 0;
45     switch(type) {
46         case WEAPON_SWORD:
47             factory = new HonorOfFighter();
48             break;
49         case WEAPON_SHIELD:
50             factory = new BliefOfDefender();
51             break;
52         // ... other cases ...
53         default:
54             break;
55     }
56     weapon = factory->createWeapon();
57     if (factory) delete factory;
58     return weapon;
59 }
60 
61 Weapon* HouseOfGlinda::getEnchantedWeapon(int type, int info) {
62     EnchantedWeaponFactory factory;
63     return factory.createEnchantedWeapon(info, type);
64 }

注意到HouseOfGlinda類中,onSale接口對客戶屏蔽了子系統中的組件(譬如說WeaponFactory以及EnchantedWeaponFactory,甚至還在建設當中的ArmorFactory),做爲客戶的小霍比特人們只須要發送請求給HouseOfGlinda對象,它就能將消息轉發給相應的子系統去處理,比方說,有人想要一把普通的劍,而另外一我的想要一面冒着火焰的盾牌:

1 VisualObject* obj1 = HouseOfGlinda::getInstance->onSale(WEAPON_SHIELD, ENCHANTED_FIRE);
2 VisualObject* obj2 = HouseOfGlinda::getInstance->onSale(WEAPON_SWORD, NOTHING);

瞧,多方便呀。此外,若是真有須要,小霍比特人仍是能夠直接訪問工坊從而得到私人定製的武器。固然經過格琳達的小屋會更加方便,這樣他們有更多時間去享受啤酒和美食的樂趣了。

一張簡單的UML圖:

特色總結

Facade模式簡單且易於理解,對於咱們來講也很經常使用。它的優勢以下:

  1. 它對客戶屏蔽子系統組件,於是減小了客戶處理的對象的數目並使得子系統使用起來更加方便。
  2. 它實現了子系統與客戶之間的鬆耦合關係,而子系統內部的功能組件每每是緊耦合的。鬆耦合關係使得子系統的組件變化不會影響到它的客戶。Facade模式有助於創建層次結構系統,也有助於對對象之間的依賴關係分層。Facade模式能夠消除複雜的循環依賴關係。這一點在客戶程序與子系統是分別實現的時候尤其重要。
  3. 若是應用須要,它並不限制它們使用子系統類。所以咱們能夠在系統易用性和通用性之間加以選擇。

寫在最後

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

相關文章
相關標籤/搜索