|
| 1 | +# Facade(外观模式) |
| 2 | + |
| 3 | +Facade(外观模式)属于结构型模式,是一种日常开发中经常被使用到的设计模式。 |
| 4 | + |
| 5 | +**意图:为子系统中的一组接口提供一个一致的界面,Facade 模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。** |
| 6 | + |
| 7 | +## 举例子 |
| 8 | + |
| 9 | +如果看不懂上面的意图介绍,没有关系,设计模式需要在日常工作里用起来,结合例子可以加深你的理解,下面我准备了三个例子,让你体会什么场景下会用到这种设计模式。 |
| 10 | + |
| 11 | +## 意图解释 |
| 12 | + |
| 13 | +### 图书管理员 |
| 14 | + |
| 15 | +图书馆是一个非常复杂的系统,虽然图书按照一定规则摆放,但也只有内部人员比较清楚,作为一位初次来的访客,想要快速找到一本书,最好的办法是直接问图书管理员,而不是先了解这个图书馆的设计,因为你可能要来回在各个楼宇间奔走,借书的流程可能也比较长。 |
| 16 | + |
| 17 | +图书管理员就起到了简化图书馆子系统复杂度的作用,我们只要凡事询问图书管理员即可,而不需要关心他是如何与图书馆内部系统打交道的。 |
| 18 | + |
| 19 | +### 最多跑一次便民服务 |
| 20 | + |
| 21 | +浙江省推出的最多跑一次服务非常方便,很多办事流程都简化了,无论是证件办理还是业务受理,几乎只要跑一次,而必须要持续几天的流程也会通过手机短信或者 App 操作完成后续流程。 |
| 22 | + |
| 23 | +这就相当于外观模式,因为政府系统内部的办事流程可能没有太大变化,但通过抽象出 Facade(外观),让普通市民可以直接与便民办事处连接,而不需要在车管所与驾校之间来回奔波,背后的事情没有少,只是便民办事处帮你做了。 |
| 24 | + |
| 25 | +### Iphone 快捷指令功能 |
| 26 | + |
| 27 | +手机的 App 非常多,而我们需要了解每个功能在哪个 App 上才能运用自如,而快捷指令功能可以将 App 的某些功能单独提取出来,形成一套新的功能组,我们可以只接触到 “拍照” “付款” “计算”,而不用管背后是调用了支付宝还是微信、系统内置摄像机还是其他摄像 App,也不用关心这个 App 内部功能的入口在哪里,这些对接都在快接指令中自动完成。 |
| 28 | + |
| 29 | +快捷指令也是一种外观模式。 |
| 30 | + |
| 31 | +## 意图解释 |
| 32 | + |
| 33 | +**意图:为子系统中的一组接口提供一个一致的界面,Facade 模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。** |
| 34 | + |
| 35 | +为降低一个拥有多个接口的子系统内部复杂性,我们需要一个外观来屏蔽内部的复杂性,因此外观模式就是定义一个高层接口,这个接口直连子系统的内部实现,但调用这个高层接口的人不需要关心子系统内部的实现,这样,对于不想了解子系统内部实现的人来说,提高了易用度。 |
| 36 | + |
| 37 | +当然如果想要深度定制,就可以绕过外观模式,直接使用子系统提供的类,所以说并不是有了外观模式就必须通过外观调用,而是根据实际需要判断使用哪种调用方式。 |
| 38 | + |
| 39 | +## 结构图 |
| 40 | + |
| 41 | +<img width=600 src="https://img.alicdn.com/tfs/TB1j9gZ3.T1gK0jSZFrXXcNCXXa-1082-412.png"> |
| 42 | + |
| 43 | +可以看到,Facade 直接指向子系统中的类,**而子系统的类不会反向指向 Facade**。 |
| 44 | + |
| 45 | +## 代码例子 |
| 46 | + |
| 47 | +下面例子使用 typescript 编写。 |
| 48 | + |
| 49 | +```typescript |
| 50 | +// 假设一个子系统是三个类结合使用的,为了抽象而解耦开了 |
| 51 | +class A { |
| 52 | + constructor(b: B) { |
| 53 | + this.b = b |
| 54 | + } |
| 55 | +} |
| 56 | + |
| 57 | +class B { |
| 58 | + constructor(c: C) { |
| 59 | + this.c = c |
| 60 | + } |
| 61 | +} |
| 62 | + |
| 63 | +class C { |
| 64 | + |
| 65 | +} |
| 66 | + |
| 67 | +// 它们组合成了一种常用功能,我们可以使用外观模式屏蔽子类的细节直接使用 |
| 68 | +class Compile { |
| 69 | + public run() { |
| 70 | + const parser = new A(new B(new C)) |
| 71 | + parser.run() |
| 72 | + } |
| 73 | +} |
| 74 | + |
| 75 | +const compile = new Compile() |
| 76 | +compile.run() |
| 77 | +``` |
| 78 | + |
| 79 | +这样我们只要知道 `Compile` 类就可以了,而不需要了解背后的 `A` `B` `C` 以及其组合关系。 |
| 80 | + |
| 81 | +## 弊端 |
| 82 | + |
| 83 | +外观模式并不适合于所有场景,当子系统足够易用时,再使用外观模式就是画蛇添足。 |
| 84 | + |
| 85 | +另外,当系统难以抽象出通用功能时,外观模式的设计可能也无所适从,因为设计的高层接口可能适用范围很窄,此时外观模式的意义就比较小。 |
| 86 | + |
| 87 | +## 总结 |
| 88 | + |
| 89 | +其实抽象工厂模式也可以代替外观模式,来实现隐藏子类具体实现的效果,但外观模式描述更具有通用性。 |
| 90 | + |
| 91 | +> 讨论地址是:[精读《设计模式 - Facade 外观模式》· Issue #286 · dt-fe/weekly](https://github.com/dt-fe/weekly/issues/288) |
| 92 | +
|
| 93 | +**如果你想参与讨论,请 [点击这里](https://github.com/dt-fe/weekly),每周都有新的主题,周末或周一发布。前端精读 - 帮你筛选靠谱的内容。** |
| 94 | + |
| 95 | +> 关注 **前端精读微信公众号** |
| 96 | +
|
| 97 | +<img width=200 src="https://img.alicdn.com/tfs/TB165W0MCzqK1RjSZFLXXcn2XXa-258-258.jpg"> |
| 98 | + |
| 99 | +> 版权声明:自由转载-非商用-非衍生-保持署名([创意共享 3.0 许可证](https://creativecommons.org/licenses/by-nc-nd/3.0/deed.zh)) |
0 commit comments