外观模式解析与Spring实战应用
1. 外观模式深度解析:从设计哲学到Spring实战
外观模式(Facade Pattern)作为GoF 23种设计模式中的结构型模式,其核心价值在于简化复杂系统的调用方式。当我们需要协调多个子系统完成某项功能时,外观模式通过提供一个统一的接口,隐藏内部复杂的交互细节,使得客户端调用变得简单直观。
1.1 模式定义与UML解析
标准外观模式包含三个关键角色:
- Facade(外观角色):封装子系统调用入口
- SubSystem(子系统角色):实际执行业务逻辑的模块
- Client(客户端):通过外观接口调用功能
典型UML类图结构如下:
┌─────────────┐ ┌──────────────────┐ │ Client │───────│ Facade │ └─────────────┘ └──────────────────┘ △ ┌───────────┴───────────┐ ┌───────┴───────┐ ┌───────┴───────┐ │ SubSystemA │ │ SubSystemB │ └───────────────┘ └───────────────┘在Spring框架中,DispatcherServlet就是典型的外观实现,它封装了HandlerMapping、HandlerAdapter等组件的复杂交互过程。
1.2 模式优势与适用场景
外观模式的核心优势体现在:
- 简化接口:减少客户端需要了解的子系统细节
- 降低耦合:客户端只依赖外观接口,不直接调用子系统
- 提高安全性:可以对外隐藏敏感子系统接口
典型适用场景包括:
- 复杂模块系统需要提供简单入口
- 子系统存在多层嵌套调用
- 需要对外隐藏敏感实现细节
- 系统需要逐步重构时作为过渡方案
2. Spring中的外观模式实现
2.1 DispatcherServlet架构解析
Spring MVC的核心控制器DispatcherServlet是外观模式的经典实现。我们来看其核心处理流程:
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) { // 1. 获取处理器执行链(外观模式中的子系统调用) HandlerExecutionChain mappedHandler = getHandler(processedRequest); // 2. 获取处理器适配器(另一个子系统) HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); // 3. 执行预处理拦截器 if (!mappedHandler.applyPreHandle(processedRequest, response)) { return; } // 4. 实际处理请求(核心子系统调用) ModelAndView mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); // 5. 执行后处理拦截器 mappedHandler.applyPostHandle(processedRequest, response, mv); }这个流程完美体现了外观模式的特点:客户端(通常是Web容器)只需要调用DispatcherServlet的service()方法,所有复杂的处理器查找、适配器选择、拦截器调用等细节都被封装在内部。
2.2 源码级实现分析
让我们深入DispatcherServlet的初始化过程:
// 初始化策略组件 protected void initStrategies(ApplicationContext context) { initMultipartResolver(context); // 文件上传解析器 initLocaleResolver(context); // 本地化解析 initThemeResolver(context); // 主题解析 initHandlerMappings(context); // 处理器映射 initHandlerAdapters(context); // 处理器适配器 initHandlerExceptionResolvers(context); // 异常解析 initRequestToViewNameTranslator(context); // 视图名转换 initViewResolvers(context); // 视图解析器 initFlashMapManager(context); // FlashMap管理器 }每个init方法都遵循"策略模式+外观模式"的组合设计:
- 从ApplicationContext获取所有特定类型的Bean
- 如果没有自定义实现,则加载默认策略
- 将组件注册到DispatcherServlet的成员变量中
这种设计使得:
- 子系统组件可以灵活替换
- 默认实现保证开箱即用
- 外观接口保持稳定不变
3. 外观模式的Spring实践
3.1 自定义外观实现案例
假设我们需要开发一个支付网关服务,整合多种支付方式:
// 支付外观接口 public interface PaymentFacade { PaymentResult pay(PaymentRequest request); PaymentResult query(String paymentId); boolean refund(RefundRequest request); } // 具体实现 @Service public class PaymentFacadeImpl implements PaymentFacade { @Autowired private AlipayService alipay; @Autowired private WechatPayService wechatPay; @Autowired private UnionPayService unionPay; @Override public PaymentResult pay(PaymentRequest request) { switch(request.getChannel()) { case ALIPAY: return alipay.createOrder(request); case WECHAT: return wechatPay.unifiedOrder(request); case UNION: return unionPay.pay(request); default: throw new UnsupportedOperationException(); } } // 其他方法实现... }这个外观实现:
- 统一了不同支付渠道的接口差异
- 隐藏了各渠道的特殊参数处理
- 提供了一致的异常处理机制
- 便于后续添加新的支付渠道
3.2 与Spring Cloud的整合
在微服务架构中,外观模式常以API Gateway的形式出现。Spring Cloud Gateway的核心组件就体现了这一思想:
@Bean public RouteLocator customRouteLocator(RouteLocatorBuilder builder) { return builder.routes() .route("order-service", r -> r.path("/api/orders/**") .filters(f -> f.addRequestHeader("X-Request-Id", UUID.randomUUID().toString())) .uri("lb://order-service")) .route("payment-service", r -> r.path("/api/payments/**") .filters(f -> f.circuitBreaker(config -> config .setName("paymentCB") .setFallbackUri("forward:/fallback"))) .uri("lb://payment-service")) .build(); }这种配置方式:
- 对外暴露统一的API入口
- 内部路由到不同的微服务
- 可以统一添加安全、限流等公共逻辑
- 客户端无需知道具体服务实例位置
4. 高级应用与性能优化
4.1 动态外观实现
对于需要运行时决定子系统的场景,可以结合策略模式实现动态外观:
public class DynamicFacade { private Map<BusinessType, SubSystem> strategies; public DynamicFacade(List<SubSystem> systems) { this.strategies = systems.stream() .collect(Collectors.toMap(SubSystem::getType, Function.identity())); } public Result handle(Request request) { SubSystem system = strategies.get(request.getType()); if (system == null) { throw new UnsupportedOperationException(); } return system.process(request); } }Spring的自动装配机制特别适合这种场景,只需定义好策略接口:
public interface SubSystem { BusinessType getType(); Result process(Request request); } @Component public class SystemA implements SubSystem { @Override public BusinessType getType() { return BusinessType.A; } @Override public Result process(Request request) { // 具体实现 } }4.2 缓存优化实践
外观模式经常需要整合多个子系统的结果,合理的缓存策略能显著提升性能:
@Cacheable(cacheNames = "compositeData", key = "#root.methodName + ':' + #param") public CompositeData getCompositeData(String param) { DataA a = serviceA.getData(param); DataB b = serviceB.query(param); DataC c = serviceC.fetch(param); return new CompositeData(a, b, c); }缓存注意事项:
- 明确缓存粒度(全量缓存 vs 部分缓存)
- 注意子系统的数据一致性
- 合理设置过期时间
- 考虑缓存穿透问题
5. 常见问题与解决方案
5.1 典型问题排查表
| 问题现象 | 可能原因 | 解决方案 |
|---|---|---|
| 调用外观方法返回null | 子系统未正确注入 | 检查@Autowired和@Component注解 |
| 部分功能不可用 | 子系统异常未被处理 | 在外观层添加统一异常处理 |
| 性能突然下降 | 子系统存在性能瓶颈 | 添加熔断机制和超时控制 |
| 返回数据不一致 | 子系统版本不一致 | 统一依赖版本和接口规范 |
5.2 调试技巧
- 日志增强:在外观层添加详细日志
@Slf4j @Service public class OrderFacade { public OrderResult createOrder(OrderRequest request) { log.debug("开始创建订单,参数:{}", request); try { OrderResult result = orderService.create(request); log.debug("订单创建成功,结果:{}", result); return result; } catch (Exception e) { log.error("订单创建失败", e); throw new BusinessException("订单创建失败"); } } }- 单元测试策略:
@SpringBootTest class OrderFacadeTest { @MockBean private OrderService orderService; @Autowired private OrderFacade orderFacade; @Test void testCreateOrderSuccess() { OrderRequest request = new OrderRequest(); when(orderService.create(any())).thenReturn(new OrderResult()); OrderResult result = orderFacade.createOrder(request); assertNotNull(result); } }- 监控指标:通过Spring Actuator暴露外观接口的指标
management: endpoints: web: exposure: include: health,metrics,prometheus metrics: tags: application: ${spring.application.name}6. 设计模式组合应用
外观模式很少单独使用,通常与其他模式组合能发挥更大威力:
6.1 外观+工厂模式
public class ParserFacade { private Map<FileType, Parser> parsers; public ParserFacade(ParserFactory factory) { this.parsers = new EnumMap<>(FileType.class); for (FileType type : FileType.values()) { parsers.put(type, factory.createParser(type)); } } public Document parse(File file) { FileType type = detectFileType(file); return parsers.get(type).parse(file); } }6.2 外观+观察者模式
public class OrderProcessingFacade { private final OrderService orderService; private final List<OrderListener> listeners; @Async public void processOrder(Order order) { Order processed = orderService.process(order); listeners.forEach(l -> l.onOrderProcessed(processed)); } }6.3 外观+模板方法模式
public abstract class ReportGeneratorFacade { public final Report generate(DataSource data) { validate(data); Report report = createReport(); populateData(report, data); formatReport(report); return report; } protected abstract void populateData(Report report, DataSource data); protected abstract void formatReport(Report report); }7. 性能考量与最佳实践
7.1 线程安全实现
当外观需要维护状态时,需考虑线程安全:
@Scope(proxyMode = ScopedProxyMode.TARGET_CLASS) public class CounterFacade { private final AtomicLong counter = new AtomicLong(); @Transactional public long increment() { return counter.incrementAndGet(); } }7.2 懒加载策略
对于初始化成本高的子系统,可以采用懒加载:
public class LazyFacade { private volatile ExpensiveService service; public void operation() { if (service == null) { synchronized (this) { if (service == null) { service = new ExpensiveService(); } } } service.doWork(); } }在Spring环境中更推荐使用@Lazy:
@Component public class MyFacade { private final ExpensiveService service; public MyFacade(@Lazy ExpensiveService service) { this.service = service; } }7.3 超时控制
整合多个子系统时,必须考虑超时控制:
@RestController @RequestMapping("/api") public class ApiFacadeController { @GetMapping("/composite") public ResponseEntity<?> getCompositeData() { try { CompletableFuture<DataA> futureA = CompletableFuture.supplyAsync( () -> serviceA.getData(), CompletableFuture.delayedExecutor(3, TimeUnit.SECONDS) ); DataB dataB = serviceB.getData(); DataA dataA = futureA.get(2, TimeUnit.SECONDS); // 超时设置 return ResponseEntity.ok(new CompositeData(dataA, dataB)); } catch (TimeoutException e) { return ResponseEntity.status(HttpStatus.GATEWAY_TIMEOUT).build(); } } }8. 现代架构中的演进
8.1 微服务架构中的API网关
现代微服务架构中,API Gateway是外观模式的升级体现:
# application.yml示例 spring: cloud: gateway: routes: - id: product-service uri: lb://product-service predicates: - Path=/api/products/** filters: - name: CircuitBreaker args: name: productCB fallbackUri: forward:/fallback/product8.2 响应式编程适配
在响应式栈中,外观模式可以这样实现:
@RestController public class ReactiveFacadeController { private final WebClient productClient; private final WebClient inventoryClient; @GetMapping("/product-details/{id}") public Mono<ProductDetails> getDetails(@PathVariable String id) { Mono<Product> product = productClient.get() .uri("/products/{id}", id) .retrieve() .bodyToMono(Product.class); Mono<Inventory> inventory = inventoryClient.get() .uri("/inventory/{productId}", id) .retrieve() .bodyToMono(Inventory.class); return Mono.zip(product, inventory) .map(tuple -> new ProductDetails(tuple.getT1(), tuple.getT2())); } }8.3 服务网格集成
在Service Mesh架构中,外观模式可以结合Sidecar实现:
@FeignClient(name = "inventory-service", configuration = FeignConfig.class, fallback = InventoryFallback.class) public interface InventoryClient { @GetMapping("/inventory/{productId}") Inventory getInventory(@PathVariable String productId); } @Configuration public class FeignConfig { @Bean public RequestInterceptor meshInterceptor() { return template -> { template.header("X-Mesh-Route", "v2"); }; } }9. 反模式与注意事项
9.1 常见误用场景
过度封装:将不相关的功能强行放在一个外观中
// 反例:混杂不相关功能 public class BadFacade { public void processOrder() {...} public void generateReport() {...} public void sendMarketingEmail() {...} }循环依赖:外观与子系统相互引用
// 反例:循环依赖 public class Facade { private SubSystemA a; public void setA(SubSystemA a) { this.a = a; } } public class SubSystemA { private Facade facade; public void setFacade(Facade f) { this.facade = f; } }性能黑洞:外观方法中进行不必要的串行调用
// 反例:串行调用可并行的操作 public Result slowMethod() { DataA a = serviceA.get(); // 耗时100ms DataB b = serviceB.get(); // 耗时150ms return combine(a, b); // 总耗时250ms }
9.2 最佳实践建议
- 单一职责:每个外观类应该只封装一组相关功能
- 接口隔离:为不同类型的客户端提供不同的外观接口
- 适度抽象:不要隐藏客户端确实需要知道的合理细节
- 性能考量:对于IO密集型操作,考虑异步或并行处理
- 版本控制:当子系统接口变化时,考虑提供多版本外观
10. Spring源码中的其他外观示例
除了DispatcherServlet,Spring中还有多个经典的外观实现:
10.1 JdbcTemplate
public class JdbcTemplate extends JdbcAccessor implements JdbcOperations { public <T> T query(String sql, ResultSetExtractor<T> rse) { return execute(sql, (StatementCallback<T>) stmt -> { ResultSet rs = stmt.executeQuery(sql); return rse.extractData(rs); }); } }这个实现:
- 封装了Connection、Statement等资源的获取和释放
- 统一处理SQLException到DataAccessException的转换
- 提供多种便捷方法(queryForObject等)
10.2 TransactionTemplate
public class TransactionTemplate extends DefaultTransactionDefinition implements TransactionOperations { public <T> T execute(TransactionCallback<T> action) { TransactionStatus status = getTransactionManager().getTransaction(this); try { T result = action.doInTransaction(status); getTransactionManager().commit(status); return result; } catch (RuntimeException ex) { rollbackOnException(status, ex); throw ex; } } }这个模板:
- 封装了事务开始、提交、回滚的完整流程
- 统一处理事务异常
- 支持编程式事务控制
10.3 RestTemplate
虽然已被WebClient取代,但RestTemplate仍是经典外观案例:
public class RestTemplate extends InterceptingHttpAccessor implements RestOperations { public <T> ResponseEntity<T> exchange(String url, HttpMethod method, HttpEntity<?> requestEntity, Class<T> responseType, Object... uriVariables) { RequestCallback requestCallback = httpEntityCallback(requestEntity, responseType); ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(responseType); return execute(url, method, requestCallback, responseExtractor, uriVariables); } }这个设计:
- 封装了HTTP请求的完整处理流程
- 提供消息转换、错误处理等基础设施
- 支持URI变量、请求头等复杂场景
11. 测试策略与Mock技巧
11.1 单元测试方案
对于外观类的测试,应该:
- 测试外观接口的各种调用组合
- 验证异常处理逻辑
- 检查对子系统的正确调用
示例测试类:
@ExtendWith(MockitoExtension.class) class OrderFacadeTest { @Mock private OrderService orderService; @Mock private PaymentService paymentService; @InjectMocks private OrderFacade orderFacade; @Test void placeOrderSuccess() { Order order = new Order(); when(orderService.create(any())).thenReturn(order); when(paymentService.process(any())).thenReturn(new PaymentResult()); OrderResult result = orderFacade.placeOrder(new OrderRequest()); assertNotNull(result); verify(orderService).create(any()); } }11.2 集成测试方案
使用SpringBootTest进行整体验证:
@SpringBootTest @AutoConfigureMockMvc class OrderFacadeIntegrationTest { @Autowired private MockMvc mockMvc; @Test void testPlaceOrder() throws Exception { mockMvc.perform(post("/orders") .contentType(MediaType.APPLICATION_JSON) .content("{\"items\":[{\"productId\":\"p1\",\"quantity\":2}]}")) .andExpect(status().isOk()) .andExpect(jsonPath("$.orderId").exists()); } }11.3 组件测试技巧
使用@TestComponent隔离测试:
@TestConfiguration static class TestConfig { @Bean @Primary public PaymentService testPaymentService() { return mock(PaymentService.class); } } @SpringBootTest class OrderFacadeComponentTest { @Autowired private PaymentService paymentService; @Autowired private OrderFacade orderFacade; @Test void testPaymentFailure() { when(paymentService.process(any())).thenThrow(new PaymentException()); assertThrows(OrderException.class, () -> orderFacade.placeOrder(new OrderRequest())); } }12. 未来演进与替代方案
12.1 面向切面的外观
结合AOP实现更灵活的外观:
@Aspect @Component public class ServiceFacadeAspect { @Around("execution(* com.example..*Service.*(..))") public Object profile(ProceedingJoinPoint pjp) throws Throwable { long start = System.currentTimeMillis(); try { return pjp.proceed(); } finally { long elapsed = System.currentTimeMillis() - start; if (elapsed > 100) { log.warn("Slow service call: {} took {}ms", pjp.getSignature(), elapsed); } } } }12.2 函数式编程风格
使用Java函数式接口简化外观:
public class FunctionalFacade { private final Function<Request, Response> handler; public FunctionalFacade(List<Processor> processors) { this.handler = processors.stream() .map(Processor::asFunction) .reduce(Function::andThen) .orElse(req -> new Response()); } public Response handle(Request request) { return handler.apply(request); } }12.3 响应式编程重构
使用Reactor实现非阻塞外观:
public class ReactiveFacade { private final OrderService orderService; private final InventoryService inventoryService; public Mono<OrderDetails> getOrderDetails(String orderId) { return orderService.findById(orderId) .zipWith(inventoryService.getStock(orderId)) .map(tuple -> new OrderDetails(tuple.getT1(), tuple.getT2())); } }13. 设计模式组合拳
13.1 外观+装饰器模式
public class AuditingFacade implements OrderFacade { private final OrderFacade delegate; private final AuditService audit; public AuditingFacade(OrderFacade delegate, AuditService audit) { this.delegate = delegate; this.audit = audit; } @Override public OrderResult placeOrder(OrderRequest request) { audit.log("Placing order", request); try { OrderResult result = delegate.placeOrder(request); audit.log("Order placed", result); return result; } catch (Exception e) { audit.log("Order failed", e); throw e; } } }13.2 外观+组合模式
public class CompositeFacade implements Component { private List<Component> children = new ArrayList<>(); public void add(Component component) { children.add(component); } @Override public void execute() { children.forEach(Component::execute); } }13.3 外观+状态模式
public class OrderWorkflowFacade { private OrderState currentState; public void process() { currentState.handle(this); } public void changeState(OrderState newState) { this.currentState = newState; } } interface OrderState { void handle(OrderWorkflowFacade facade); }14. 性能监控与调优
14.1 Micrometer指标集成
public class MonitoredFacade { private final MeterRegistry registry; private final Counter successCounter; private final Timer timer; public MonitoredFacade(MeterRegistry registry) { this.registry = registry; this.successCounter = registry.counter("facade.operations", "type", "success"); this.timer = registry.timer("facade.latency"); } public void operation() { timer.record(() -> { try { // 业务逻辑 successCounter.increment(); } catch (Exception e) { registry.counter("facade.operations", "type", "failure").increment(); throw e; } }); } }14.2 分布式追踪集成
@Slf4j public class TracedFacade { private final Tracer tracer; public void process() { Span span = tracer.nextSpan().name("facade-operation").start(); try (var ws = tracer.withSpan(span)) { // 业务逻辑 span.tag("result", "success"); } catch (Exception e) { span.error(e); span.tag("result", "failure"); throw e; } finally { span.finish(); } } }14.3 性能优化示例
public class OptimizedFacade { private final Executor executor = Executors.newFixedThreadPool(4); public CompletableFuture<CompositeResult> fetchData() { CompletableFuture<DataA> futureA = CompletableFuture.supplyAsync( () -> serviceA.getData(), executor); CompletableFuture<DataB> futureB = CompletableFuture.supplyAsync( () -> serviceB.getData(), executor); return futureA.thenCombine(futureB, CompositeResult::new); } }15. 安全考量与实践
15.1 输入验证
public class SecureFacade { public void process(UserInput input) { if (!isValid(input)) { throw new ValidationException("Invalid input"); } // 处理逻辑 } private boolean isValid(UserInput input) { // 实现验证逻辑 } }15.2 权限控制
@PreAuthorize("hasRole('ADMIN')") public class AdminFacade { @PreAuthorize("#user.id == authentication.principal.id") public void adminOperation(User user) { // 敏感操作 } }15.3 审计日志
@Aspect @Component public class AuditAspect { @AfterReturning( pointcut = "execution(* com.example..*Facade.*(..))", returning = "result") public void auditSuccess(JoinPoint jp, Object result) { auditService.logSuccess(jp.getSignature(), jp.getArgs(), result); } @AfterThrowing( pointcut = "execution(* com.example..*Facade.*(..))", throwing = "ex") public void auditFailure(JoinPoint jp, Exception ex) { auditService.logFailure(jp.getSignature(), jp.getArgs(), ex); } }16. 复杂业务场景应用
16.1 分布式事务协调
public class DistributedTxFacade { @Transactional public void distributedOperation() { try { // 阶段1:准备 boolean prepared = prepare(); // 阶段2:提交或回滚 if (prepared) { commit(); } else { rollback(); } } catch (Exception e) { rollback(); throw e; } } }16.2 业务规则引擎集成
public class RulesFacade { private final KieContainer kieContainer; public Order applyDiscounts(Order order) { KieSession session = kieContainer.newKieSession(); try { session.insert(order); session.fireAllRules(); return order; } finally { session.dispose(); } } }16.3 工作流引擎集成
public class WorkflowFacade { private final RuntimeService runtimeService; public void startProcess(BusinessData data) { Map<String, Object> variables = new HashMap<>(); variables.put("data", data); runtimeService.startProcessInstanceByKey("businessProcess", variables); } }17. 容器化与云原生适配
17.1 Kubernetes健康检查
@RestController @RequestMapping("/health") public class HealthFacade { @GetMapping public ResponseEntity<?> health() { if (checkComponents()) { return ResponseEntity.ok().build(); } return ResponseEntity.status(503).build(); } private boolean checkComponents() { // 检查所有子系统健康状态 } }17.2 配置热更新
@RefreshScope @Service public class ConfigurableFacade { @Value("${facade.timeout:1000}") private long timeout; public void operation() { // 使用动态配置 } }17.3 服务网格集成
public class MeshFacade { private final WebClient client; public MeshFacade(WebClient.Builder builder) { this.client = builder .filter(ExchangeFilterFunctions .basicAuthentication("user", "pass")) .build(); } }18. 前沿技术融合
18.1 AI服务集成
public class AiFacade { private final AiClient aiClient; public AnalysisResult analyze(Data data) { AiRequest request = new AiRequest(data); AiResponse response = aiClient.analyze(request); return transform(response); } }18.2 区块链服务集成
public class BlockchainFacade { private final BlockchainClient client; public TransactionReceipt submit(ContractCall call) { return client.execute(call) .block(Duration.ofSeconds(30)); } }18.3 物联网平台集成
public class IoTFacade { private final MqttClient mqtt; public void sendCommand(DeviceCommand command) { mqtt.publish("commands", command.toBytes()); } }19. 架构演进建议
19.1 从单体到微服务
迁移路径建议:
- 先在内部分解为逻辑模块
- 通过外观模式提供统一接口
- 逐步将模块拆分为独立服务
- 用API Gateway替代原有外观
19.2 前后端分离架构
前端友好设计:
@RestController @RequestMapping("/api") public class ApiFacade { @GetMapping("/composite") public CompositeData getComposite() { // 聚合多个后端服务数据 } }19.3 Serverless适配
函数式外观:
@Bean public Function<Input, Output> facadeFunction(ServiceA a, ServiceB b) { return input -> { // 组合服务调用 }; }20. 总结与个人实践心得
在实际项目中应用外观模式时,我有几点深刻体会:
接口设计至关重要:外观接口应该保持稳定,即使内部实现变化也不应影响客户端
合理划分边界:不要试图用一个外观类解决所有问题,应该按业务领域划分
性能考量:对于需要聚合多个子系统结果的场景,考虑异步并行调用
错误处理:统一将子系统异常转换为客户端友好的错误表示
测试策略:外观层应该有自己的测试套件,独立于子系统测试
一个典型的Spring项目中,我会这样组织外观层:
src/ ├── main/ │ ├── java/ │ │ └── com/ │ │ └── example/ │ │ ├── facade/ │ │ │ ├── OrderFacade.java │ │ │ ├── PaymentFacade.java │ │ │ └── config/ │ │ │ └── FacadeConfig.java │ │ └── subsystem/ │ │ ├── internal/ │ │ └── service/ └── test/ └── java/ └── com/ └── example/ └── facade/ ├── OrderFacadeTest.java └── PaymentFacadeTest.java最后分享一个实用技巧:在开发初期,可以先用外观模式封装不稳定的子系统接口,这样当子系统API发生变化时,只需要修改外观层内部实现,而不会影响业务代码。这种设计特别适合与第三方系统集成的场景。