这是 2020 年 5 月整理的设计模式专题第八篇。外观模式又叫门面模式,是”化繁为简”的代表——把一堆复杂的子系统接口,收敛成一个简单统一的入口。就像前台:你只需要跟前台说需求,不用自己去对接各个部门。
简单说明
外观模式(Facade Pattern),又叫门面模式:提供一个统一的接口,来访问子系统的一群接口。
- 在子系统越来越复杂的时候,可以用外观模式提供简单的接口调用;
- 或者构建多层系统结构的时候,利用外观对象作为每层的入口,简化层间调用。
客户端 ──> 外观对象(Facade)──> 子系统A
│ ├─> 子系统B
│ └─> 子系统C
(客户端只依赖门面,不直接接触子系统)
实现
将子系统各种接口聚合,对外展示 Facade 对象:
/**
* 描述:子系统:订单系统
*/
public class OrderService {
public void createOrder() {
System.out.println("创建订单");
}
}
/**
* 描述:子系统:库存系统
*/
public class StockService {
public void deductStock() {
System.out.println("扣减库存");
}
}
/**
* 描述:子系统:支付系统
*/
public class PayService {
public void pay() {
System.out.println("完成支付");
}
}
/**
* 描述:外观对象:聚合所有子系统,对外提供一个简单入口
*/
public class OrderFacade {
private OrderService orderService = new OrderService();
private StockService stockService = new StockService();
private PayService payService = new PayService();
// 一键下单:客户端只调这一个方法
public void placeOrder() {
orderService.createOrder();
stockService.deductStock();
payService.pay();
}
}
/**
* 描述:客户端
*/
public class Client {
public static void main(String[] args) {
// 客户端完全不需要知道 OrderService/StockService/PayService 的存在
OrderFacade facade = new OrderFacade();
facade.placeOrder();
}
}
角色:子系统(OrderService/StockService/PayService)+ 外观(OrderFacade)。客户端只依赖外观,不直接接触子系统。
优点与缺点
优点:
- 简化调用过程:无需了解深入子系统,防止带来风险(客户端接触的接口变少,出错面变小);
- 减少系统依赖:松散耦合(客户端与子系统解耦,只依赖门面);
- 更好的划分访问层次:门面对象作为每层入口,层间调用清晰;
- 符合迪米特法则:客户端只跟”朋友”(门面)打交道,不跟陌生人(子系统)通信。
缺点:
- 增加子系统、扩展子系统行为时容易引入风险;
- 不符合开闭原则:如果子系统行为变化需要修改门面,门面本身变成脆弱点。
外观模式对”调用方”友好,但对”扩展方”不友好——门面把复杂收敛了,代价是门面自身成为修改的集中点。
适用场景
- 子系统越来越复杂,需要提供一个简单的对外接口;
- 构建分层架构,用门面作为每一层的入口;
- 希望降低客户端与子系统的耦合度;
- 对老系统进行防腐:把遗留系统的复杂接口用门面包装起来。
外观 vs 适配器
| 对比项 | 外观模式 | 适配器模式 |
|---|---|---|
| 目的 | 简化子系统访问,提供统一入口 | 转换接口,让不兼容的接口协同 |
| 面向 | 面向子系统(多个) | 面向单个接口 |
| 核心 | 化繁为简 | 桥接不匹配 |
小结
- 外观模式提供统一的接口访问子系统的一群接口,是”化繁为简”的门面。
- 实现:将子系统接口聚合,对外暴露 Facade 对象。
- 四个优点:简化调用、减少依赖、划分层次、符合迪米特法则。
- 两个缺点:扩展子系统易引入风险、不符合开闭原则。
- 一句话:客户端只跟”前台”打交道,不用逐个对接背后的部门。