【设计模式手册023】外观模式 - 如何简化复杂系统

【设计模式手册023】外观模式 - 如何简化复杂系统

1. 我们为何需要外观模式?

在软件设计中,我们经常会遇到这样的场景:一个系统由多个复杂的子系统组成,客户端需要与这些子系统进行交互,但直接交互会导致客户端代码复杂且难以维护。比如:

  • 家庭影院系统:打开投影仪、打开音响、调暗灯光、播放电影
  • 电商下单系统:库存检查、价格计算、优惠券验证、支付处理、物流创建
  • 计算机启动系统:CPU自检、内存检查、设备初始化、系统加载
  • 微服务调用:用户服务、订单服务、支付服务、库存服务

初级程序员的写法

java 复制代码
// 客户端直接调用所有子系统
public class HomeTheaterClient {
    private Projector projector;
    private Amplifier amplifier;
    private Lights lights;
    private DVDPlayer dvdPlayer;
    
    public void watchMovie(String movie) {
        // 需要了解所有子系统的接口和调用顺序
        projector.on();
        projector.setInput("DVD");
        
        amplifier.on();
        amplifier.setVolume(5);
        amplifier.setSource("DVD");
        
        lights.dim(10);
        
        dvdPlayer.on();
        dvdPlayer.play(movie);
        
        System.out.println("开始观看电影: " + movie);
    }
    
    public void endMovie() {
        // 同样需要了解关闭顺序
        dvdPlayer.stop();
        dvdPlayer.off();
        
        lights.on();
        
        amplifier.off();
        
        projector.off();
    }
}

这种写法的痛点

  • 客户端复杂度高:客户端需要了解所有子系统的接口
  • 紧耦合:客户端与多个子系统紧密耦合
  • 难以维护:子系统变化会影响所有客户端
  • 重复代码:相同的调用逻辑在多个地方重复

2. 外观模式:本质与定义

2.1 模式定义

外观模式(Facade Pattern):为子系统中的一组接口提供一个一致的界面,外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。

2.2 模式结构

java 复制代码
// 子系统A
public class SubsystemA {
    public void operationA() {
        System.out.println("执行子系统A的操作");
    }
}

// 子系统B
public class SubsystemB {
    public void operationB() {
        System.out.println("执行子系统B的操作");
    }
}

// 子系统C
public class SubsystemC {
    public void operationC() {
        System.out.println("执行子系统C的操作");
    }
}

// 外观类
public class Facade {
    private SubsystemA subsystemA;
    private SubsystemB subsystemB;
    private SubsystemC subsystemC;
    
    public Facade() {
        this.subsystemA = new SubsystemA();
        this.subsystemB = new SubsystemB();
        this.subsystemC = new SubsystemC();
    }
    
    // 简化后的高层接口
    public void simplifiedOperation() {
        System.out.println("外观模式简化操作开始");
        subsystemA.operationA();
        subsystemB.operationB();
        subsystemC.operationC();
        System.out.println("外观模式简化操作结束");
    }
}

// 客户端代码
public class Client {
    public static void main(String[] args) {
        Facade facade = new Facade();
        facade.simplifiedOperation(); // 只需调用一个方法
    }
}

3. 深入理解

3.1 接口简化

核心思想:将复杂的子系统调用封装成简单的高层接口。

java 复制代码
// 复杂的使用方式
public class ComplexClient {
    public void complexOperation() {
        ServiceA a = new ServiceA();
        ServiceB b = new ServiceB();
        ServiceC c = new ServiceC();
        
        a.initialize();
        b.setup();
        c.prepare();
        
        a.execute();
        b.process();
        c.run();
        
        a.cleanup();
        b.finish();
        c.dispose();
    }
}

// 简化的使用方式
public class SimpleClient {
    public void simpleOperation() {
        Facade facade = new Facade();
        facade.easyOperation(); // 一个方法搞定
    }
}

3.2 依赖倒置

设计原则的体现:客户端不再依赖具体的子系统,而是依赖外观接口。

java 复制代码
// 不好的做法:客户端直接依赖多个子系统
public class BadClient {
    private ServiceA serviceA;
    private ServiceB serviceB;
    private ServiceC serviceC;
    // 依赖太多,耦合度高
}

// 好的做法:客户端只依赖外观
public class GoodClient {
    private Facade facade;
    // 只依赖一个外观,耦合度低
}

3.3 使用接口进一步解耦

通过接口定义外观,让客户端只依赖抽象外观,不依赖具体外观实现。

java 复制代码
// 外观接口
public interface HomeTheaterFacade {
    void watchMovie(String movie);
    void endMovie();
    void listenToMusic(String music);
}

// 具体外观实现
public class BasicHomeTheaterFacade implements HomeTheaterFacade {
    // 实现接口方法
}

// 客户端只依赖接口
public class Client {
    private HomeTheaterFacade facade;
    
    public Client(HomeTheaterFacade facade) {
        this.facade = facade;
    }
}

4. 实战案例:完整的智能家居控制系统

让我们来看一个完整的例子:

java 复制代码
// 子系统类 - 各种智能设备
@Slf4j
public class LightSystem {
    public void on() {
        log.info("灯光系统:打开所有灯光");
    }
    
    public void off() {
        log.info("灯光系统:关闭所有灯光");
    }
    
    public void dim(int level) {
        log.info("灯光系统:调暗灯光到 {}%", level);
    }
    
    public void setColor(String color) {
        log.info("灯光系统:设置灯光颜色为 {}", color);
    }
}

@Slf4j
public class AudioSystem {
    public void on() {
        log.info("音响系统:打开音响");
    }
    
    public void off() {
        log.info("音响系统:关闭音响");
    }
    
    public void setVolume(int level) {
        log.info("音响系统:设置音量为 {}", level);
    }
    
    public void setSource(String source) {
        log.info("音响系统:设置音源为 {}", source);
    }
    
    public void playMusic(String music) {
        log.info("音响系统:播放音乐 {}", music);
    }
    
    public void stopMusic() {
        log.info("音响系统:停止播放音乐");
    }
}

@Slf4j
public class VideoSystem {
    public void on() {
        log.info("视频系统:打开视频设备");
    }
    
    public void off() {
        log.info("视频系统:关闭视频设备");
    }
    
    public void setInput(String input) {
        log.info("视频系统:设置输入源为 {}", input);
    }
    
    public void playMovie(String movie) {
        log.info("视频系统:播放电影 {}", movie);
    }
    
    public void stopMovie() {
        log.info("视频系统:停止播放电影");
    }
}

@Slf4j
public class ClimateSystem {
    public void setTemperature(double temperature) {
        log.info("空调系统:设置温度为 {}°C", temperature);
    }
    
    public void setMode(String mode) {
        log.info("空调系统:设置模式为 {}", mode);
    }
    
    public void turnOn() {
        log.info("空调系统:打开空调");
    }
    
    public void turnOff() {
        log.info("空调系统:关闭空调");
    }
}

@Slf4j
public class SecuritySystem {
    public void arm() {
        log.info("安防系统:布防");
    }
    
    public void disarm() {
        log.info("安防系统:撤防");
    }
    
    public void lockDoors() {
        log.info("安防系统:锁门");
    }
    
    public void unlockDoors() {
        log.info("安防系统:解锁门");
    }
}

@Slf4j
public class CurtainSystem {
    public void open() {
        log.info("窗帘系统:打开窗帘");
    }
    
    public void close() {
        log.info("窗帘系统:关闭窗帘");
    }
}

// 外观接口
public interface SmartHomeFacade {
    // 场景模式
    void enterHomeMode();
    void leaveHomeMode();
    void movieMode(String movie);
    void partyMode(String music);
    void sleepMode();
    void wakeUpMode();
    
    // 单个设备控制
    void controlLights(boolean on, Integer dimLevel, String color);
    void controlAudio(boolean on, Integer volume, String source);
    void controlClimate(double temperature, String mode);
}

// 具体外观实现
@Slf4j
public class SmartHomeFacadeImpl implements SmartHomeFacade {
    private final LightSystem lightSystem;
    private final AudioSystem audioSystem;
    private final VideoSystem videoSystem;
    private final ClimateSystem climateSystem;
    private final SecuritySystem securitySystem;
    private final CurtainSystem curtainSystem;
    
    public SmartHomeFacadeImpl() {
        this.lightSystem = new LightSystem();
        this.audioSystem = new AudioSystem();
        this.videoSystem = new VideoSystem();
        this.climateSystem = new ClimateSystem();
        this.securitySystem = new SecuritySystem();
        this.curtainSystem = new CurtainSystem();
    }
    
    @Override
    public void enterHomeMode() {
        log.info("=== 进入回家模式 ===");
        securitySystem.disarm();
        securitySystem.unlockDoors();
        lightSystem.on();
        climateSystem.turnOn();
        climateSystem.setTemperature(22.0);
        climateSystem.setMode("舒适");
        audioSystem.on();
        audioSystem.setVolume(20);
        audioSystem.playMusic("欢迎回家音乐");
        log.info("=== 回家模式设置完成 ===\n");
    }
    
    @Override
    public void leaveHomeMode() {
        log.info("=== 进入离家模式 ===");
        audioSystem.stopMusic();
        audioSystem.off();
        lightSystem.off();
        climateSystem.turnOff();
        curtainSystem.close();
        securitySystem.lockDoors();
        securitySystem.arm();
        log.info("=== 离家模式设置完成 ===\n");
    }
    
    @Override
    public void movieMode(String movie) {
        log.info("=== 进入观影模式 ===");
        curtainSystem.close();
        lightSystem.dim(10);
        lightSystem.setColor("暖黄");
        climateSystem.setTemperature(24.0);
        climateSystem.setMode("静音");
        audioSystem.on();
        audioSystem.setVolume(30);
        audioSystem.setSource("电影");
        videoSystem.on();
        videoSystem.setInput("HDMI");
        videoSystem.playMovie(movie);
        log.info("=== 观影模式设置完成,开始播放: {} ===\n", movie);
    }
    
    @Override
    public void partyMode(String music) {
        log.info("=== 进入派对模式 ===");
        curtainSystem.open();
        lightSystem.on();
        lightSystem.setColor("多彩");
        climateSystem.setTemperature(20.0);
        climateSystem.setMode("通风");
        audioSystem.on();
        audioSystem.setVolume(60);
        audioSystem.setSource("蓝牙");
        audioSystem.playMusic(music);
        log.info("=== 派对模式设置完成,播放音乐: {} ===\n", music);
    }
    
    @Override
    public void sleepMode() {
        log.info("=== 进入睡眠模式 ===");
        audioSystem.stopMusic();
        audioSystem.off();
        videoSystem.stopMovie();
        videoSystem.off();
        lightSystem.dim(5);
        lightSystem.setColor("暖黄");
        climateSystem.setTemperature(20.0);
        climateSystem.setMode("睡眠");
        curtainSystem.close();
        securitySystem.arm();
        log.info("=== 睡眠模式设置完成 ===\n");
    }
    
    @Override
    public void wakeUpMode() {
        log.info("=== 进入唤醒模式 ===");
        curtainSystem.open();
        lightSystem.on();
        lightSystem.setColor("自然白");
        climateSystem.setTemperature(22.0);
        climateSystem.setMode("舒适");
        audioSystem.on();
        audioSystem.setVolume(15);
        audioSystem.playMusic("清晨音乐");
        securitySystem.disarm();
        log.info("=== 唤醒模式设置完成 ===\n");
    }
    
    @Override
    public void controlLights(boolean on, Integer dimLevel, String color) {
        log.info("=== 灯光控制 ===");
        if (on) {
            lightSystem.on();
            if (dimLevel != null) {
                lightSystem.dim(dimLevel);
            }
            if (color != null) {
                lightSystem.setColor(color);
            }
        } else {
            lightSystem.off();
        }
        log.info("=== 灯光控制完成 ===\n");
    }
    
    @Override
    public void controlAudio(boolean on, Integer volume, String source) {
        log.info("=== 音响控制 ===");
        if (on) {
            audioSystem.on();
            if (volume != null) {
                audioSystem.setVolume(volume);
            }
            if (source != null) {
                audioSystem.setSource(source);
            }
        } else {
            audioSystem.off();
        }
        log.info("=== 音响控制完成 ===\n");
    }
    
    @Override
    public void controlClimate(double temperature, String mode) {
        log.info("=== 空调控制 ===");
        climateSystem.turnOn();
        climateSystem.setTemperature(temperature);
        if (mode != null) {
            climateSystem.setMode(mode);
        }
        log.info("=== 空调控制完成 ===\n");
    }
}

// 客户端代码
@Slf4j
public class SmartHomeClient {
    private SmartHomeFacade smartHome;
    
    public SmartHomeClient(SmartHomeFacade smartHome) {
        this.smartHome = smartHome;
    }
    
    public void simulateDailyRoutine() {
        log.info("开始模拟智能家居日常场景\n");
        
        // 早上起床
        log.info("7:00 AM - 起床时间");
        smartHome.wakeUpMode();
        
        // 出门上班
        log.info("8:30 AM - 出门上班");
        smartHome.leaveHomeMode();
        
        // 下班回家
        log.info("6:00 PM - 下班回家");
        smartHome.enterHomeMode();
        
        // 晚上看电影
        log.info("8:00 PM - 家庭影院时间");
        smartHome.movieMode("阿凡达");
        
        // 准备睡觉
        log.info("11:00 PM - 睡觉时间");
        smartHome.sleepMode();
        
        log.info("日常场景模拟结束");
    }
    
    public void controlIndividualDevices() {
        log.info("开始单个设备控制演示\n");
        
        // 单独控制灯光
        smartHome.controlLights(true, 80, "自然白");
        
        // 单独控制音响
        smartHome.controlAudio(true, 25, "FM收音机");
        
        // 单独控制空调
        smartHome.controlClimate(23.5, "自动");
    }
}

// 使用示例
public class FacadePatternDemo {
    public static void main(String[] args) {
        // 创建外观
        SmartHomeFacade smartHome = new SmartHomeFacadeImpl();
        
        // 创建客户端
        SmartHomeClient client = new SmartHomeClient(smartHome);
        
        // 演示场景模式
        System.out.println("====== 场景模式演示 ======");
        client.simulateDailyRoutine();
        
        // 演示单个设备控制
        System.out.println("\n====== 单个设备控制演示 ======");
        client.controlIndividualDevices();
        
        // 演示直接使用外观
        System.out.println("\n====== 直接外观调用演示 ======");
        smartHome.partyMode("派对音乐");
    }
}

5. Spring Boot中的实现

在Spring Boot中,我们可以利用依赖注入让外观模式更加优雅:

java 复制代码
// 微服务客户端(模拟)
@Component
@Slf4j
public class UserServiceClient {
    public User getUserById(String userId) {
        log.info("用户服务:获取用户信息,用户ID: {}", userId);
        return new User(userId, "张三", "zhangsan@example.com");
    }
    
    public boolean validateUser(String userId) {
        log.info("用户服务:验证用户,用户ID: {}", userId);
        return true;
    }
}

@Component
@Slf4j
public class InventoryServiceClient {
    public boolean checkInventory(String productId, int quantity) {
        log.info("库存服务:检查库存,产品ID: {},数量: {}", productId, quantity);
        return quantity <= 100; // 模拟库存检查
    }
    
    public void reduceInventory(String productId, int quantity) {
        log.info("库存服务:减少库存,产品ID: {},数量: {}", productId, quantity);
    }
}

@Component
@Slf4j
public class PricingServiceClient {
    public BigDecimal calculatePrice(String productId, int quantity, String couponCode) {
        log.info("价格服务:计算价格,产品ID: {},数量: {},优惠券: {}", productId, quantity, couponCode);
        BigDecimal basePrice = new BigDecimal("99.99");
        BigDecimal total = basePrice.multiply(BigDecimal.valueOf(quantity));
        
        // 模拟优惠券逻辑
        if ("DISCOUNT10".equals(couponCode)) {
            total = total.multiply(new BigDecimal("0.9"));
        }
        
        return total;
    }
    
    public boolean validateCoupon(String couponCode) {
        log.info("价格服务:验证优惠券: {}", couponCode);
        return couponCode == null || "DISCOUNT10".equals(couponCode);
    }
}

@Component
@Slf4j
public class PaymentServiceClient {
    public PaymentResult processPayment(String orderId, BigDecimal amount, PaymentMethod method) {
        log.info("支付服务:处理支付,订单ID: {},金额: {},支付方式: {}", orderId, amount, method);
        
        // 模拟支付处理
        boolean success = Math.random() > 0.1; // 90%成功率
        
        if (success) {
            return new PaymentResult(true, "支付成功", UUID.randomUUID().toString());
        } else {
            return new PaymentResult(false, "支付失败", null);
        }
    }
}

@Component
@Slf4j
public class ShippingServiceClient {
    public ShippingInfo createShipping(String orderId, String address) {
        log.info("物流服务:创建物流,订单ID: {},地址: {}", orderId, address);
        return new ShippingInfo(UUID.randomUUID().toString(), "顺丰快递", "已揽收");
    }
}

// 订单外观服务
@Service
@Slf4j
public class OrderFacadeService {
    private final UserServiceClient userService;
    private final InventoryServiceClient inventoryService;
    private final PricingServiceClient pricingService;
    private final PaymentServiceClient paymentService;
    private final ShippingServiceClient shippingService;
    
    public OrderFacadeService(UserServiceClient userService,
                            InventoryServiceClient inventoryService,
                            PricingServiceClient pricingService,
                            PaymentServiceClient paymentService,
                            ShippingServiceClient shippingService) {
        this.userService = userService;
        this.inventoryService = inventoryService;
        this.pricingService = pricingService;
        this.paymentService = paymentService;
        this.shippingService = shippingService;
    }
    
    @Transactional
    public OrderResult placeOrder(OrderRequest request) {
        log.info("开始处理订单请求: {}", request);
        
        try {
            // 1. 验证用户
            if (!userService.validateUser(request.getUserId())) {
                return OrderResult.failure("用户验证失败");
            }
            
            // 2. 验证优惠券
            if (!pricingService.validateCoupon(request.getCouponCode())) {
                return OrderResult.failure("优惠券无效");
            }
            
            // 3. 检查库存
            if (!inventoryService.checkInventory(request.getProductId(), request.getQuantity())) {
                return OrderResult.failure("库存不足");
            }
            
            // 4. 计算价格
            BigDecimal totalAmount = pricingService.calculatePrice(
                request.getProductId(), request.getQuantity(), request.getCouponCode());
            
            // 5. 处理支付
            PaymentResult paymentResult = paymentService.processPayment(
                request.getOrderId(), totalAmount, request.getPaymentMethod());
            
            if (!paymentResult.isSuccess()) {
                return OrderResult.failure("支付失败: " + paymentResult.getMessage());
            }
            
            // 6. 减少库存
            inventoryService.reduceInventory(request.getProductId(), request.getQuantity());
            
            // 7. 创建物流
            ShippingInfo shippingInfo = shippingService.createShipping(
                request.getOrderId(), request.getShippingAddress());
            
            // 8. 获取用户信息
            User user = userService.getUserById(request.getUserId());
            
            log.info("订单处理成功: {}", request.getOrderId());
            
            return OrderResult.success(
                request.getOrderId(),
                totalAmount,
                paymentResult.getTransactionId(),
                shippingInfo.getTrackingNumber(),
                user
            );
            
        } catch (Exception e) {
            log.error("订单处理失败: {}", request.getOrderId(), e);
            return OrderResult.failure("系统错误: " + e.getMessage());
        }
    }
    
    public OrderStatus checkOrderStatus(String orderId) {
        log.info("检查订单状态: {}", orderId);
        
        // 模拟状态检查
        // 在实际系统中,这里会查询各个服务的状态
        
        return new OrderStatus(orderId, "已完成", LocalDateTime.now());
    }
}

// DTO类
@Data
@AllArgsConstructor
class User {
    private String userId;
    private String name;
    private String email;
}

@Data
@AllArgsConstructor
class PaymentResult {
    private boolean success;
    private String message;
    private String transactionId;
}

@Data
@AllArgsConstructor
class ShippingInfo {
    private String trackingNumber;
    private String shippingCompany;
    private String status;
}

@Data
class OrderRequest {
    private String orderId;
    private String userId;
    private String productId;
    private int quantity;
    private String couponCode;
    private PaymentMethod paymentMethod;
    private String shippingAddress;
    
    public OrderRequest() {
        this.orderId = "ORDER_" + System.currentTimeMillis();
    }
}

enum PaymentMethod {
    ALIPAY, WECHAT, CREDIT_CARD
}

@Data
@AllArgsConstructor
class OrderResult {
    private boolean success;
    private String orderId;
    private BigDecimal totalAmount;
    private String transactionId;
    private String trackingNumber;
    private User user;
    private String message;
    
    public static OrderResult success(String orderId, BigDecimal totalAmount, 
                                    String transactionId, String trackingNumber, User user) {
        return new OrderResult(true, orderId, totalAmount, transactionId, trackingNumber, user, "订单创建成功");
    }
    
    public static OrderResult failure(String message) {
        return new OrderResult(false, null, null, null, null, null, message);
    }
}

@Data
@AllArgsConstructor
class OrderStatus {
    private String orderId;
    private String status;
    private LocalDateTime updateTime;
}

// REST控制器
@RestController
@RequestMapping("/api/orders")
@Slf4j
public class OrderController {
    private final OrderFacadeService orderFacadeService;
    
    public OrderController(OrderFacadeService orderFacadeService) {
        this.orderFacadeService = orderFacadeService;
    }
    
    @PostMapping("/place")
    public ResponseEntity<OrderResult> placeOrder(@RequestBody OrderRequest request) {
        log.info("收到下单请求: {}", request);
        
        OrderResult result = orderFacadeService.placeOrder(request);
        
        if (result.isSuccess()) {
            return ResponseEntity.ok(result);
        } else {
            return ResponseEntity.badRequest().body(result);
        }
    }
    
    @GetMapping("/{orderId}/status")
    public ResponseEntity<OrderStatus> getOrderStatus(@PathVariable String orderId) {
        OrderStatus status = orderFacadeService.checkOrderStatus(orderId);
        return ResponseEntity.ok(status);
    }
}

// 配置类
@Configuration
@Slf4j
public class AppConfig {
    
    @Bean
    @Order(1)
    public CommandLineRunner demo(OrderFacadeService orderFacadeService) {
        return args -> {
            log.info("开始外观模式演示...");
            
            // 模拟订单请求
            OrderRequest request = new OrderRequest();
            request.setUserId("USER_001");
            request.setProductId("PRODUCT_001");
            request.setQuantity(2);
            request.setCouponCode("DISCOUNT10");
            request.setPaymentMethod(PaymentMethod.ALIPAY);
            request.setShippingAddress("北京市朝阳区xxx街道");
            
            OrderResult result = orderFacadeService.placeOrder(request);
            
            if (result.isSuccess()) {
                log.info("订单创建成功: {}", result.getOrderId());
                log.info("订单金额: {}", result.getTotalAmount());
                log.info("交易ID: {}", result.getTransactionId());
                log.info("物流单号: {}", result.getTrackingNumber());
            } else {
                log.error("订单创建失败: {}", result.getMessage());
            }
        };
    }
}

6. 外观模式的变体与进阶用法

6.1 多层外观模式

对于特别复杂的系统,可以设计多层外观:

java 复制代码
// 底层外观
@Service
@Slf4j
public class PaymentFacadeService {
    private final PaymentGateway paymentGateway;
    private final FraudDetectionService fraudDetection;
    private final NotificationService notificationService;
    
    public PaymentResult processPayment(PaymentRequest request) {
        // 反欺诈检查
        if (!fraudDetection.check(request)) {
            return PaymentResult.failure("反欺诈检查失败");
        }
        
        // 支付处理
        PaymentResult result = paymentGateway.process(request);
        
        // 发送通知
        if (result.isSuccess()) {
            notificationService.sendPaymentSuccess(request, result);
        }
        
        return result;
    }
}

// 高层外观
@Service
@Slf4j
public class OrderManagementFacadeService {
    private final OrderFacadeService orderFacade;
    private final PaymentFacadeService paymentFacade;
    private final InventoryFacadeService inventoryFacade;
    
    public CompleteOrderResult processCompleteOrder(CompleteOrderRequest request) {
        // 使用各个底层外观完成复杂业务流程
        OrderResult orderResult = orderFacade.placeOrder(request.getOrderRequest());
        
        if (!orderResult.isSuccess()) {
            return CompleteOrderResult.failure(orderResult.getMessage());
        }
        
        // 其他业务逻辑...
        
        return CompleteOrderResult.success(orderResult);
    }
}

6.2 可配置的外观模式

通过配置决定使用哪些子系统:

java 复制代码
@Configuration
@Slf4j
public class FacadeConfiguration {
    
    @Bean
    @ConditionalOnProperty(name = "features.advanced-audio", havingValue = "true")
    public AudioSystem advancedAudioSystem() {
        return new AdvancedAudioSystem();
    }
    
    @Bean
    @ConditionalOnProperty(name = "features.advanced-audio", havingValue = "false", matchIfMissing = true)
    public AudioSystem basicAudioSystem() {
        return new BasicAudioSystem();
    }
    
    @Bean
    public SmartHomeFacade smartHomeFacade(AudioSystem audioSystem, 
                                          LightSystem lightSystem,
                                          @Value("${features.mode:basic}") String mode) {
        if ("advanced".equals(mode)) {
            return new AdvancedSmartHomeFacade(audioSystem, lightSystem);
        } else {
            return new BasicSmartHomeFacade(audioSystem, lightSystem);
        }
    }
}

7. 外观模式 vs 其他模式

7.1 外观模式 vs 中介者模式

  • 外观模式:简化客户端与子系统的交互,单向通信
  • 中介者模式:协调多个对象之间的交互,双向通信

7.2 外观模式 vs 适配器模式

  • 外观模式:简化接口,让现有系统更容易使用
  • 适配器模式:转换接口,让不兼容的接口能够一起工作

7.3 外观模式 vs 门面模式

  • 外观模式:其实就是门面模式,只是翻译不同
  • 两者是同一个模式的不同称呼

8. 总结与思考

8.1 外观模式的优点

  1. 简化客户端:客户端只需要与外观对象交互,无需了解复杂子系统
  2. 松耦合:客户端与子系统解耦,子系统变化不影响客户端
  3. 易于使用:提供简单一致的高层接口
  4. 层次化:可以定义多层外观,管理不同层次的复杂度

8.2 外观模式的缺点

  1. 不够灵活:如果客户端需要访问子系统的特定功能,可能受到限制
  2. 增加复杂度:引入了新的抽象层
  3. 单点故障:外观对象成为系统的单点故障

8.3 深入思考

外观模式的本质是**"复杂度的封装"**。它通过在复杂系统前设置一个简单的接口,隐藏系统的复杂性,让客户端能够以最简单的方式使用系统功能。

设计之美的思考

"外观模式就像现实世界中的客户服务中心。当你遇到问题时,不需要知道公司内部有哪些部门、每个部门的职责是什么,只需要拨打一个统一的客服电话,客服人员会帮你协调所有相关部门解决问题。这种'一站式服务'的理念,极大地提升了用户体验。"

从源码的角度看,外观模式在Java中有着广泛应用:

  • Spring Framework 的 JdbcTemplate 封装了复杂的JDBC操作
  • SLF4J 日志门面封装了各种日志实现
  • Java AWT 的 Graphics 类封装了复杂的图形绘制操作
  • Tomcat 的 HttpServletRequestHttpServletResponse 封装了HTTP协议细节

何时使用外观模式

  • 要为复杂的子系统提供简单接口时
  • 客户端与多个子系统之间存在很多依赖关系时
  • 需要层次化子系统时,可以使用外观模式定义每层的入口点
  • 需要解耦客户端与子系统时

使用场景

  • 智能家居控制系统
  • 微服务架构中的API网关
  • 复杂库或框架的简单入口
  • 遗留系统的现代化包装
  • 多层架构中的层间通信

版权声明:本文为CSDN博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

相关推荐
独自归家的兔2 小时前
面试实录:三大核心问题深度拆解(三级缓存 + 工程规范 + 逻辑思维)
java·后端·面试·职场和发展
毕设源码-郭学长2 小时前
【开题答辩全过程】以 共享单车后台管理系统为例,包含答辩的问题和答案
java·开发语言·tomcat
北城以北88882 小时前
SpringBoot--SpringBoot集成RabbitMQ
java·spring boot·rabbitmq·java-rabbitmq
Zsh-cs2 小时前
SpringMVC
java·springmvc
用户8307196840822 小时前
Java 并发进化史:从踩坑到躺赢
java
傻啦嘿哟2 小时前
Python在Excel中创建与优化数据透视表的完整指南
java·前端·spring
uup2 小时前
异常的 “隐藏传递”:finally 中的 return 会吞噬异常?
java
白露与泡影2 小时前
春招 Java 面试大纲:Java+ 并发 +spring+ 数据库 +Redis+JVM+Netty 等
java·数据库·面试
roman_日积跬步-终至千里2 小时前
【多线程】 Spring 无状态 Service 线程安全设计实战
java·安全·spring