跳到主要内容

外观模式

问题

什么是外观(门面)模式?在 Java 项目中如何应用?

答案

核心思想

为子系统中的一组复杂接口提供一个统一的高层接口,客户端只需与外观类交互,不用关心子系统的内部细节。

实现示例

外观模式 - 下单流程
// 复杂的子系统
@Service
public class InventoryService {
public boolean checkStock(String productId, int qty) { /* ... */ return true; }
public void deductStock(String productId, int qty) { /* ... */ }
}

@Service
public class PaymentService {
public PayResult pay(String orderId, BigDecimal amount) { /* ... */ return null; }
}

@Service
public class ShippingService {
public String createShipment(String orderId, String address) { /* ... */ return ""; }
}

// 外观类:封装下单的复杂流程,对外暴露简单接口
@Service
public class OrderFacade {
@Autowired private InventoryService inventoryService;
@Autowired private PaymentService paymentService;
@Autowired private ShippingService shippingService;

/**
* 一键下单:封装库存检查 → 支付 → 发货的复杂流程
*/
public OrderResult placeOrder(OrderRequest request) {
// 1. 检查库存
if (!inventoryService.checkStock(request.getProductId(), request.getQuantity())) {
return OrderResult.fail("库存不足");
}

// 2. 扣减库存
inventoryService.deductStock(request.getProductId(), request.getQuantity());

// 3. 发起支付
PayResult payResult = paymentService.pay(request.getOrderId(), request.getAmount());
if (!payResult.isSuccess()) {
return OrderResult.fail("支付失败");
}

// 4. 创建物流
String trackingNo = shippingService.createShipment(
request.getOrderId(), request.getAddress());

return OrderResult.success(trackingNo);
}
}

// Controller 只需调用外观类
@RestController
public class OrderController {
@Autowired
private OrderFacade orderFacade;

@PostMapping("/orders")
public OrderResult createOrder(@RequestBody OrderRequest request) {
return orderFacade.placeOrder(request);
}
}

Java/Spring 中的典型应用

应用说明
SLF4J统一日志门面,屏蔽底层日志框架差异
Spring JdbcTemplate封装 JDBC 繁琐的连接/关闭/异常处理
Spring RestTemplate封装 HTTP 调用细节
BFF 层后端聚合多个微服务,提供统一 API 给前端
Service 层封装多个 DAO 的调用逻辑
外观模式 ≈ 分层封装

Java 项目的 Controller → Service → DAO 三层架构天然就是外观模式的应用:

  • Service 是 DAO 的外观
  • Controller 是 Service 的外观
  • BFF 是多个微服务的外观

常见面试问题

Q1: 外观模式和代理模式的区别?

答案

维度外观模式代理模式
目的简化多个子系统的复杂接口控制对单个对象的访问
对象数封装多个子系统代理一个目标对象
接口提供新的简化接口与目标对象接口相同

Q2: 外观模式的缺点?

答案

  1. 外观类可能变成"上帝类"(God Class),承担过多职责
  2. 新增子系统功能需要修改外观类
  3. 不符合开闭原则

解决方案:将外观类拆分为多个领域外观(如 OrderFacadeUserFacade),每个只负责一个业务领域。

相关链接