外观模式
外观模式
Metadata
title: 外观模式
date: 2022-12-19 21:03
tags:
- 行动阶段/完成
- 主题场景/设计
- 笔记空间/KnowladgeSpace/ProgramSpace/ProjectSpace
- 细化主题/设计模式/结构模式/外观模式
categories:
- 设计
keywords:
- 设计模式/结构模式/外观模式
description: 外观模式是一种结构型设计模式, 能为程序库、 框架或其他复杂类提供一个简单的接口。
外观模式是一种结构型设计模式, 能为程序库、 框架或其他复杂类提供一个简单的接口。
简介
意图:
为子系统中的一组接口提供一个一致的界面,外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。
主要解决:
降低访问复杂系统的内部子系统时的复杂度,简化客户端之间的接口。
何时使用:
- 客户端不需要知道系统内部的复杂联系,整个系统只需提供一个 “接待员” 即可。
- 定义系统的入口。
如何解决:
客户端不与系统耦合,外观类与系统耦合。
关键代码:
在客户端和复杂系统之间再加一层,这一层将调用顺序、依赖关系等处理好。
应用实例:
- 去医院看病,可能要去挂号、门诊、划价、取药,让患者或患者家属觉得很复杂,如果有提供接待人员,只让接待人员来处理,就很方便。
- JAVA 的三层开发模式。
优点:
- 减少系统相互依赖。
- 提高灵活性。
- 提高了安全性。
缺点:
不符合开闭原则,如果要改东西很麻烦,继承重写都不合适。
使用场景:
- 为复杂的模块或子系统提供外界访问的模块。
- 子系统相对独立。
- 预防低水平人员带来的风险。
注意事项:
在层次化结构中,可以使用外观模式定义系统中每一层的入口。
模式结构
- 外观 (Facade) 提供了一种访问特定子系统功能的便捷方式, 其了解如何重定向客户端请求, 知晓如何操作一切活动部件。
- 创建附加外观 (Additional Facade) 类可以避免多种不相关的功能污染单一外观, 使其变成又一个复杂结构。 客户端和其他外观都可使用附加外观。
- 复杂子系统 (Complex Subsystem) 由数十个不同对象构成。 如果要用这些对象完成有意义的工作, 你必须深入了解子系统的实现细节, 比如按照正确顺序初始化对象和为其提供正确格式的数据。
- 子系统类不会意识到外观的存在, 它们在系统内运作并且相互之间可直接进行交互。
- 客户端 (Client) 使用外观代替对子系统对象的直接调用。
适合应用场景
title: 如果你需要一个指向复杂子系统的直接接口, 且该接口的功能有限, 则可以使用外观模式。
子系统通常会随着时间的推进变得越来越复杂。 即便是应用了设计模式, 通常你也会创建更多的类。 尽管在多种情形中子系统可能是更灵活或易于复用的, 但其所需的配置和样板代码数量将会增长得更快。 为了解决这个问题, 外观将会提供指向子系统中最常用功能的快捷方式, 能够满足客户端的大部分需求。
title: 如果需要将子系统组织为多层结构, 可以使用外观。
创建外观来定义子系统中各层次的入口。 你可以要求子系统仅使用外观来进行交互, 以减少子系统之间的耦合。
让我们回到视频转换框架的例子。 该框架可以拆分为两个层次: 音频相关和视频相关。 你可以为每个层次创建一个外观, 然后要求各层的类必须通过这些外观进行交互。 这种方式看上去与中介者模式非常相似。
实现方式
- 考虑能否在现有子系统的基础上提供一个更简单的接口。 如果该接口能让客户端代码独立于众多子系统类, 那么你的方向就是正确的。
- 在一个新的外观类中声明并实现该接口。 外观应将客户端代码的调用重定向到子系统中的相应对象处。 如果客户端代码没有对子系统进行初始化, 也没有对其后续生命周期进行管理, 那么外观必须完成此类工作。
- 如果要充分发挥这一模式的优势, 你必须确保所有客户端代码仅通过外观来与子系统进行交互。 此后客户端代码将不会受到任何由子系统代码修改而造成的影响, 比如子系统升级后, 你只需修改外观中的代码即可。
- 如果外观变得过于臃肿, 你可以考虑将其部分行为抽取为一个新的专用外观类。
示例
优缺点
title: 优点
- 你可以让自己的代码独立于复杂子系统。
缺点
- 外观可能成为与程序中所有类都耦合的上帝对象。
与其他模式的关系
[[外观模式]]为现有对象定义了一个新接口, [[适配器模式]]则会试图运用已有的接口。 适配器通常只封装一个对象, 外观通常会作用于整个对象子系统上。
当只需对客户端代码隐藏子系统创建对象的方式时, 你可以使用[[../创建模式/抽象工厂模式]]来代替[[外观模式]]。
[[享元模式]]展示了如何生成大量的小型对象, [[外观模式]]则展示了如何用一个对象来代表整个子系统。
[[外观模式]]和[[中介者模式]]的职责类似: 它们都尝试在大量紧密耦合的类中组织起合作。
[[外观模式]]为子系统中的所有对象定义了一个简单接口, 但是它不提供任何新功能。 子系统本身不会意识到外观的存在。 子系统中的对象可以直接进行交流。
中介者将系统中组件的沟通行为中心化。 各组件只知道中介者对象, 无法直接相互交流。
外观类通常可以转换为[[../创建模式/单例模式]]类, 因为在大部分情况下一个外观对象就足够了。
外观与[[代理模式]]的相似之处在于它们都缓存了一个复杂实体并自行对其进行初始化。 代理与其服务对象遵循同一接口, 使得自己和服务对象可以互换, 在这一点上它与外观不同。