设计模式设计模式外观模式 - 桑尼号的狮吼炮
苏丙榅
配套视频课程已更新完毕,大家可通过以下两种方式观看视频讲解:
关注公众号:爱编程的大丙,或者进入大丙课堂学习。
1. 开炮
桑尼号是草帽一伙的第二艘海贼船,设计者是弗兰奇,使用的材料是价值不菲、世界上最强的巨树“亚当”。主要特色是狮子造形的船头及“士兵船坞系统”,此外还有草皮做成的甲板,附有大型水族馆的房间、图书馆等许多方便的设备。
桑尼号船头的狮吼炮是一个非常厉害的武器。它能够从狮嘴发射出威力超强的加农炮,可利用狮头内部操控室的“狙击圈”自由网罗目标。要发动狮吼炮必须同时使用两桶可乐的能量‘风来喷射’才可以避免后座力让船飞退。
想要发射狮吼炮,操作很简单:瞄准目标,拉动拉杆就可以发射了。但是看似简单的加农炮发射,其底层是需要很多个系统协同配合才能完成的:
- 可乐注入系统
- 能量转换系统,将注入的可乐转换成能量
- 瞄准系统
- 目标锁定系统
- 加农炮控制系统
- 风来炮稳定系统,抵消后坐力,让船体稳定。
这么复杂的系统对于使用者来说其实就是一个按钮加一个拉杆。不论狮吼炮的设计者弗兰奇有没有学过设计模式,但他确实用到了一种设计模式:外观模式。外观模式就是给很多复杂的子系统提供一个简单的上层接口,并在这些接口中包含用户真正关心的功能。
关于外观模式的应用,在实际生活中也有有很多的场景:
- 通过电商平台下单,就可以收到自己需要的商品。
- 上层接口:用于下单、查看物流信息、确认收货的用户界面
- 底层模块:供货商、仓库、包装、送货、支付处理、售后等
- 购买基金
- 上层接口:可供用户操作的UI界面
- 底层模块:基金分类、购买股票、购买国债、购买企业债
- 音频转换工具
- 上层接口:可供用户操作的UI界面
- 底层模块:MP3编解码模块、FALC编解码模块、APE编解码模块、等。。。
- 智能家居系统
- 上层接口:可供用户操作的UI界面
- 底层模块:电视、灯、热水器、空调、路由器、。。。。
2. 庖丁解牛
2.1 UML类图
关于桑尼号的狮吼炮的组成前边已经描述过了,我们需要通过外观模式对其进行封装,如果仔细分析一下可以得知,上层的接口和底层的各个模块之间应该是关联关系(因为类之间没有继承关系,也不是整体和部分这种结构,因此排除了聚合和组合,并且它们之间具有包含和被包含的关系,所以确定的关系是关联关系),下面是狮吼炮对应的UML类图:
2.2 子系统
根据上面提供的类图就可以把对应的程序写出来了:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
| class CokeSystem { public: void immitCoke() { cout << "狮吼炮原料<可乐>已经注入完毕..." << endl; } };
class EnergySystem { public: void energyConvert() { cout << "已经将所有的可乐转换为了能量..." << endl; } };
class AimLockSystem { public: void aimLock() { cout << "已经瞄准并且锁定了目标..." << endl; } };
class Cannon { public: void cannonFire() { cout << "狮吼炮正在向目标开火..." << endl; } };
class WindCannon { public: void windCannonFire() { cout << "发射风来炮抵消后坐力稳定船身..." << endl; } };
|
这些子系统都是可以独立工作的,并且都提供了供外部调用的接口。
2.3 狮吼炮
狮吼炮是上层接口,需要协调上面的这些子系统使它们能够相互配合协同工作。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| class LionCannon { public: LionCannon() { m_coke = new CokeSystem; m_energy = new EnergySystem; m_aimLock = new AimLockSystem; m_cannon = new Cannon; m_windCannon = new WindCannon; } ~LionCannon() { delete m_coke; delete m_energy; delete m_aimLock; delete m_cannon; delete m_windCannon; } void aimAndLock() { m_coke->immitCoke(); m_energy->energyConvert(); m_aimLock->aimLock(); } void fire() { m_cannon->cannonFire(); m_windCannon->windCannonFire(); } private: CokeSystem* m_coke = nullptr; EnergySystem* m_energy = nullptr; AimLockSystem* m_aimLock = nullptr; Cannon* m_cannon = nullptr; WindCannon* m_windCannon = nullptr; };
|
在狮吼炮上层接口类中只提供了两个方法:瞄准锁定 aimAndLock()
和开火 fire()
。这样对于狮吼炮的操作难度瞬间变成了傻瓜级,只要有手并且眼睛不瞎就可以操作。
2.4 开炮
最后需要展示一下狮吼炮的威力:
1 2 3 4 5 6 7 8 9
| int main() { LionCannon* lion = new LionCannon; lion->aimAndLock(); lion->fire(); delete lion; return 0; }
|
输出的结果为:
1 2 3 4 5
| 狮吼炮原料<可乐>已经注入完毕... 已经将所有的可乐转换为了能量... 已经瞄准并且锁定了目标... 狮吼炮正在向目标开火... 发射风来炮抵消后坐力稳定船身...
|
外观模式是一个很重要、平时也经常使用的设计模式,其核心思想就是化繁为简,封装底层逻辑,将使用者真正关心的功能通过上层接口呈现出来。