模式补全
这一节按 八面剖析以理解一个概念 / ljg-learn 的思路整理为 Markdown 版本:先定锚,再用八个方向切开概念,最后压缩成公式、例子、类图和检验题。
定锚
外观模式(结构型)的通行定义:为复杂子系统提供一个简单统一的入口,降低客户端使用成本。
常见误解:外观不是为了隐藏所有能力;它提供常用路径,同时保留子系统可被高级使用的可能。
核心词素:Facade 是建筑正立面:外面看到一个整洁入口,里面可以很复杂。
八刀
历史
它来自分层系统和复杂库封装。GoF 将“统一入口简化调用”作为结构型模式。
辩证
反面是客户端直接编排多个子系统。更高理解是:把常见用例沉淀成稳定入口。
现象
一键导出视频时,你不想手动调用解码、滤镜、压缩、上传四个模块。
语言
Facade 是建筑正立面:外面看到一个整洁入口,里面可以很复杂。
形式
Client → Facade → Subsystems。若外观承担太多业务决策,会变成上帝类。
存在
它让复杂性退到幕后,让使用者先完成任务,再逐步理解内部。
美感
它美在门厅:把混乱走廊收束成一个清楚入口。
元反思
正立面隐喻容易让人只想遮丑。换成“快捷方式”隐喻,会更重视常用流程的准确表达。
内观
我是子系统的前台。你告诉我目标,我替你安排内部步骤。我简化入口,但不假装内部不存在。
八刀共同指向的深层结构:外观模式不是为了“炫技”,而是在某个变化点上建立边界,让稳定部分继续稳定,让变化部分有自己的位置。
压缩
公式:外观 = 统一入口 + 子系统编排 + 简化常用路径
一句话:外观模式把复杂子系统的常用调用收成一个好用入口。
结构图:
Client -> Facade -> A/B/C subsystem动机/意图
当一个子系统由多个类协作完成,客户端需要知道太多调用顺序和细节时,使用成本会很高。外观模式的意图是提供一个统一、简洁的入口,封装常用流程,降低客户端和复杂子系统之间的耦合。
结构/角色
Facade:外观类,对外暴露简化接口,内部编排多个子系统。SubsystemClass:子系统类,负责具体功能,可以彼此协作。Client:客户端优先调用外观,而不是直接协调所有子系统。AdditionalFacade:可选角色,为不同客户端提供不同粒度的外观。
典型 UML
classDiagram class Client class Facade { +operation(): void } class SubsystemA { +operationA(): void } class SubsystemB { +operationB(): void } class SubsystemC { +operationC(): void } Client ..> Facade Facade ..> SubsystemA Facade ..> SubsystemB Facade ..> SubsystemC
使用场景
- 子系统复杂,客户端只需要常用路径。
- 需要为一组底层 API 提供更稳定、更领域化的入口。
- 希望分层架构中上层只依赖少数入口。
- 初始化、关闭、事务或工作流需要统一编排。
正例:TypeScript
class Decoder {
decode(file: string) {
return "raw:" + file
}
}
class Compressor {
compress(raw: string) {
return "zip:" + raw
}
}
class VideoFacade {
constructor(
private decoder = new Decoder(),
private compressor = new Compressor(),
) {}
exportMp4(file: string) {
const raw = this.decoder.decode(file)
return this.compressor.compress(raw)
}
}正例:UML 类图
classDiagram class VideoFacade { +exportMp4(file): string } class Decoder class Compressor class Client Client --> VideoFacade VideoFacade o-- Decoder VideoFacade o-- Compressor
反例:TypeScript
function exportVideo(file: string) {
const raw = new Decoder().decode(file)
const compressed = new Compressor().compress(raw)
return compressed
}反例:UML 类图
classDiagram class Client class Decoder class Compressor Client ..> Decoder Client ..> Compressor
案例
现在考察一个电源总开关的例子,以便进一步说明外观模式。为了使用方便,一个电源总开关可以控制四盏灯、一个风扇、一台空调和一台电视机的启动和关闭。通过该电源总开关可以同时控制上述所有电器设备,使用外观模式设计该系统。
某系统需要提供一个文件加密模块,加密流程包括三个操作,分别是读取源文件、加密、保存加密之后的文件。读取文件和保存文件使用流来实现,这三个操作相对独立,其业务代码封装在三个不同的类中。现在需要提供一个统一的加密外观类,用户可以直接使用该加密外观类完成文件的读取、加密和保存三个操作,而不需要与每一个类进行交互,使用外观模式设计该加密模块。
掌握检验
- 外观模式降低的是哪一类复杂度?
- 外观和适配器都改变入口,它们的动机有什么不同?
- 外观类膨胀成上帝类时,应该如何拆?