外观模式(Facade Pattern)是一种结构型设计模式,它为复杂子系统提供一个统一的简化接口,客户端通过这个接口与子系统交互,而无需直接操作子系统中的多个组件。
简单来说,外观模式就像 “前台服务员”—— 当你去餐厅吃饭时,不需要直接和厨房、吧台、保洁等多个部门打交道,只需告诉前台服务员你的需求,由他协调协调内部各部门完成工作。
其UML类图如下:

从类图中我们不难看出,外观模式中:
- 一个Facade外观:封装了ABC三个子系统,它负责与客户端直接通信
- 子系统ABC:是实现了具体功能的系统,他们之间彼此没有依赖
外观模式的核心价值是降低复杂度和解耦,通过引入外观类隔离客户端与子系统,让客户端更易用,同时保护子系统内部细节不被暴露。常见应用场景包括:框架的 API 封装(如 Spring 的JdbcTemplate简化 JDBC 操作)、复杂工具类的统一接口(如日志门面 SLF4J)等。
我们通过一个例子来说明。假设我们有一个电商系统,其中的订单支付后的处理场景包括了“库存扣减、订单状态更新、物流创建和短信通知”。他们分别由不同的子系统完成。那么这个流程可以通过外观模式实现,把其他几个子系统的处理封装到一个Facade中,从而降低了对其他子系统的耦合,也提高了安全性。
首先,假设我们有以下几个子系统的代码:
- 库存子系统,负责扣减库存
1 2 3 4 5 6 7 8
| class InventorySystem { public boolean reduceStock(String productId, int quantity) { System.out.println("[库存系统] 校验商品[" + productId + "]库存..."); System.out.println("[库存系统] 扣减库存:商品ID=" + productId + ",数量=" + quantity); return true; } }
|
- 订单子系统中的方法完成了订单状态的更改
1 2 3 4 5 6 7
| class OrderSystem { public void updateOrderStatus(String orderId, String status) { System.out.println("[订单系统] 校验订单[" + orderId + "]当前状态..."); System.out.println("[订单系统] 订单状态更新为:" + status + "(订单ID=" + orderId + ")"); } }
|
- 物流子系统中的方法负责创建物流单
1 2 3 4 5 6 7 8 9
| class LogisticsSystem { public String createLogisticsOrder(String orderId, String recipientAddress) { System.out.println("[物流系统] 为订单[" + orderId + "]匹配快递公司..."); String logisticsNo = "SF1234567890"; System.out.println("[物流系统] 生成物流单:单号=" + logisticsNo + ",收货地址=" + recipientAddress); return logisticsNo; } }
|
- 通知子系统负责发出短信通知客户
1 2 3 4 5 6 7
| class NotificationSystem { public void sendPaymentSuccessSms(String phone, String orderId, String logisticsNo) { String message = "【电商平台】您的订单(" + orderId + ")已支付成功,物流单号:" + logisticsNo + ",请注意查收!"; System.out.println("[通知系统] 向手机号[" + phone + "]发送短信:" + message); } }
|
现在我们来创建一个Facade类,来封装上述四个子系统的方法,让它在订单支付后完成一系列操作
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
| class PaymentPostProcessFacade { private final InventorySystem inventorySystem; private final OrderSystem orderSystem; private final LogisticsSystem logisticsSystem; private final NotificationSystem notificationSystem;
public PaymentPostProcessFacade() { this.inventorySystem = new InventorySystem(); this.orderSystem = new OrderSystem(); this.logisticsSystem = new LogisticsSystem(); this.notificationSystem = new NotificationSystem(); }
public void processAfterPayment(String orderId, String productId, int quantity, String recipientAddress, String userPhone) { try { boolean stockReduced = inventorySystem.reduceStock(productId, quantity); if (!stockReduced) { throw new RuntimeException("库存不足,支付后处理失败"); }
orderSystem.updateOrderStatus(orderId, "PAID");
String logisticsNo = logisticsSystem.createLogisticsOrder(orderId, recipientAddress);
notificationSystem.sendPaymentSuccessSms(userPhone, orderId, logisticsNo);
System.out.println("\n[支付后处理完成] 订单[" + orderId + "]所有后续操作执行成功!"); } catch (Exception e) { System.err.println("[支付后处理失败] 原因:" + e.getMessage()); } } }
|
接下来,在客户端调用时,只需调用Facade类中的一个方法即可完成上述步骤
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| public class EcommerceClient { public static void main(String[] args) { String orderId = "ORDER_20240925_001"; String productId = "PROD_10086"; int quantity = 2; String recipientAddress = "北京市朝阳区XX街道"; String userPhone = "13800138000";
PaymentPostProcessFacade facade = new PaymentPostProcessFacade(); facade.processAfterPayment(orderId, productId, quantity, recipientAddress, userPhone); } }
|
从上面的例子中我们可以看出Facade模式的优势:
- 简化调用:客户端只需调用
processAfterPayment一个方法,无需逐一调用 4 个子系统的接口,降低了代码复杂度。
- 隔离变化:若子系统逻辑修改(如库存系统增加 “库存预警” 步骤),只需修改外观类,客户端代码无需变动,符合 “开闭原则”。
- 统一流程:外观类封装了子系统的调用顺序(如必须先扣库存,再更新订单状态),避免客户端因调用顺序错误导致业务异常。
- 降低耦合:客户端与子系统完全解耦,未来替换子系统(如将短信通知换成 APP 推送),客户端无需感知。