[学习笔记]设计模式之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. 若是应用须要,它并不限制它们使用子系统类。所以咱们能够在系统易用性和通用性之间加以选择。

写在最后

今天的笔记就到这里了,欢迎你们批评指正!若是以为能够的话,好文推荐一下,我会很是感谢的!

相关文章
相关标签/搜索