23种设计模式23种设计模式
首页
介绍
  • 单例模式
  • 工厂方法模式
  • 抽象工厂模式
  • 建造者模式
  • 原型模式
  • 适配器模式
  • 桥接模式
  • 组合模式
  • 装饰器模式
  • 外观模式
  • 享元模式
  • 代理模式
  • 责任链模式
  • 命令模式
  • 解释器模式
  • 迭代器模式
  • 中介者模式
  • 备忘录模式
  • 观察者模式
  • 状态模式
  • 策略模式
  • 模板方法模式
  • 访问者模式
🚀 编程指南
首页
介绍
  • 单例模式
  • 工厂方法模式
  • 抽象工厂模式
  • 建造者模式
  • 原型模式
  • 适配器模式
  • 桥接模式
  • 组合模式
  • 装饰器模式
  • 外观模式
  • 享元模式
  • 代理模式
  • 责任链模式
  • 命令模式
  • 解释器模式
  • 迭代器模式
  • 中介者模式
  • 备忘录模式
  • 观察者模式
  • 状态模式
  • 策略模式
  • 模板方法模式
  • 访问者模式
🚀 编程指南
  • 结构型模式

    • 适配器模式 (Adapter)
    • 桥接模式 (Bridge)
    • 组合模式 (Composite)
    • 装饰器模式 (Decorator)
    • 外观模式 (Facade)
    • 享元模式 (Flyweight)
    • 代理模式 (Proxy)

外观模式 (Facade)

📖 通俗理解

想象你去饭店吃饭:

  • 自己做饭:买菜 → 洗菜 → 切菜 → 炒菜 → 装盘 → 洗碗(好累!)
  • 去饭店:只需要说"来份宫保鸡丁",服务员搞定一切

饭店就是一个外观,它把复杂的做菜过程封装起来,对外只提供一个简单的接口:"点菜"。

外观模式就是:为复杂的子系统提供一个统一的、简单的接口。

🎯 解决什么问题?

问题:系统中有很多子模块,客户端需要分别调用它们,很麻烦。

// 没有外观模式,客户端需要这样做:
CPU cpu = new CPU();
Memory memory = new Memory();
HardDrive hd = new HardDrive();

cpu.freeze();
memory.load(0, hd.read(0, 1024));
cpu.jump(0);
cpu.execute();

解决:提供一个外观类,把复杂的调用封装起来。

// 有了外观模式,只需要:
Computer computer = new Computer();
computer.start();

🌰 生活中的例子

  • 一键启动汽车:按一下按钮,自动完成解锁、通电、启动等
  • 点外卖:下单即可,不用关心商家如何做、骑手如何送
  • 遥控器:一个按钮开电视,不用手动调信号、亮度等
  • 智能家居:"回家模式"一键开灯、开空调、关窗帘

💻 Java 代码实现

场景:电脑启动

电脑启动需要 CPU、内存、硬盘等多个组件协同工作,我们用外观模式封装这个过程。

第一步:定义子系统

/**
 * 子系统:CPU
 */
public class CPU {
    
    public void freeze() {
        System.out.println("CPU: 冻结处理器...");
    }
    
    public void jump(long position) {
        System.out.println("CPU: 跳转到位置 " + position);
    }
    
    public void execute() {
        System.out.println("CPU: 执行指令...");
    }
}

/**
 * 子系统:内存
 */
public class Memory {
    
    public void load(long position, byte[] data) {
        System.out.println("内存: 加载数据到位置 " + position + 
                          ",大小: " + data.length + " bytes");
    }
}

/**
 * 子系统:硬盘
 */
public class HardDrive {
    
    public byte[] read(long lba, int size) {
        System.out.println("硬盘: 从扇区 " + lba + " 读取 " + size + " 字节");
        return new byte[size];
    }
}

/**
 * 子系统:电源
 */
public class Power {
    
    public void on() {
        System.out.println("电源: 接通电源...");
    }
    
    public void off() {
        System.out.println("电源: 断开电源...");
    }
}

/**
 * 子系统:BIOS
 */
public class BIOS {
    
    public void check() {
        System.out.println("BIOS: 自检中...");
    }
    
    public void loadBootSector() {
        System.out.println("BIOS: 加载引导扇区...");
    }
}

第二步:创建外观类

/**
 * 外观类:电脑
 * 封装了所有子系统的复杂交互
 */
public class Computer {
    
    private CPU cpu;
    private Memory memory;
    private HardDrive hardDrive;
    private Power power;
    private BIOS bios;
    
    public Computer() {
        this.cpu = new CPU();
        this.memory = new Memory();
        this.hardDrive = new HardDrive();
        this.power = new Power();
        this.bios = new BIOS();
    }
    
    /**
     * 开机 - 对外提供的简单接口
     */
    public void start() {
        System.out.println("====== 电脑开机 ======");
        
        // 1. 接通电源
        power.on();
        
        // 2. BIOS 自检
        bios.check();
        bios.loadBootSector();
        
        // 3. CPU 初始化
        cpu.freeze();
        
        // 4. 从硬盘读取数据到内存
        byte[] bootData = hardDrive.read(0, 1024);
        memory.load(0, bootData);
        
        // 5. CPU 执行
        cpu.jump(0);
        cpu.execute();
        
        System.out.println("====== 开机完成 ======");
    }
    
    /**
     * 关机 - 对外提供的简单接口
     */
    public void shutdown() {
        System.out.println("====== 电脑关机 ======");
        
        cpu.freeze();
        power.off();
        
        System.out.println("====== 关机完成 ======");
    }
}

第三步:使用外观

public class Client {
    public static void main(String[] args) {
        // 用户只需要这样操作:
        Computer computer = new Computer();
        
        // 一键开机
        computer.start();
        
        System.out.println("\n... 使用电脑中 ...\n");
        
        // 一键关机
        computer.shutdown();
    }
}

输出:

====== 电脑开机 ======
电源: 接通电源...
BIOS: 自检中...
BIOS: 加载引导扇区...
CPU: 冻结处理器...
硬盘: 从扇区 0 读取 1024 字节
内存: 加载数据到位置 0,大小: 1024 bytes
CPU: 跳转到位置 0
CPU: 执行指令...
====== 开机完成 ======

... 使用电脑中 ...

====== 电脑关机 ======
CPU: 冻结处理器...
电源: 断开电源...
====== 关机完成 ======

🔥 实战案例:订单系统

电商下单涉及多个子系统:库存、支付、物流、通知等。

/**
 * 子系统:库存服务
 */
public class InventoryService {
    
    public boolean checkStock(String productId, int quantity) {
        System.out.println("库存服务: 检查商品 " + productId + " 库存...");
        return true;  // 假设有库存
    }
    
    public void reduceStock(String productId, int quantity) {
        System.out.println("库存服务: 扣减商品 " + productId + " 库存 " + quantity + " 件");
    }
}

/**
 * 子系统:支付服务
 */
public class PaymentService {
    
    public boolean pay(String orderId, double amount) {
        System.out.println("支付服务: 订单 " + orderId + " 支付 ¥" + amount);
        return true;  // 假设支付成功
    }
    
    public void refund(String orderId, double amount) {
        System.out.println("支付服务: 订单 " + orderId + " 退款 ¥" + amount);
    }
}

/**
 * 子系统:物流服务
 */
public class ShippingService {
    
    public String createShipment(String orderId, String address) {
        String trackingNumber = "SF" + System.currentTimeMillis();
        System.out.println("物流服务: 创建运单 " + trackingNumber + 
                          ",收货地址: " + address);
        return trackingNumber;
    }
}

/**
 * 子系统:通知服务
 */
public class NotificationService {
    
    public void sendSMS(String phone, String message) {
        System.out.println("通知服务: 发送短信到 " + phone + ": " + message);
    }
    
    public void sendEmail(String email, String subject, String content) {
        System.out.println("通知服务: 发送邮件到 " + email + ": " + subject);
    }
}

/**
 * 外观类:订单服务
 */
public class OrderFacade {
    
    private InventoryService inventoryService;
    private PaymentService paymentService;
    private ShippingService shippingService;
    private NotificationService notificationService;
    
    public OrderFacade() {
        this.inventoryService = new InventoryService();
        this.paymentService = new PaymentService();
        this.shippingService = new ShippingService();
        this.notificationService = new NotificationService();
    }
    
    /**
     * 下单 - 统一接口,封装复杂流程
     */
    public boolean placeOrder(String orderId, String productId, 
                              int quantity, double amount,
                              String address, String phone) {
        
        System.out.println("========== 开始处理订单 " + orderId + " ==========");
        
        // 1. 检查库存
        if (!inventoryService.checkStock(productId, quantity)) {
            System.out.println("库存不足,下单失败!");
            return false;
        }
        
        // 2. 扣减库存
        inventoryService.reduceStock(productId, quantity);
        
        // 3. 支付
        if (!paymentService.pay(orderId, amount)) {
            System.out.println("支付失败,回滚库存...");
            // 这里应该回滚库存
            return false;
        }
        
        // 4. 创建物流
        String trackingNumber = shippingService.createShipment(orderId, address);
        
        // 5. 发送通知
        notificationService.sendSMS(phone, 
            "您的订单 " + orderId + " 已发货,运单号: " + trackingNumber);
        
        System.out.println("========== 订单处理完成 ==========");
        return true;
    }
}

使用方式:

public class Client {
    public static void main(String[] args) {
        OrderFacade orderFacade = new OrderFacade();
        
        // 客户端只需要调用一个方法
        boolean success = orderFacade.placeOrder(
            "ORD20240115001",  // 订单号
            "SKU12345",        // 商品ID
            2,                 // 数量
            299.00,            // 金额
            "北京市朝阳区xxx", // 地址
            "13800138000"      // 手机号
        );
        
        System.out.println("\n下单" + (success ? "成功" : "失败"));
    }
}

输出:

========== 开始处理订单 ORD20240115001 ==========
库存服务: 检查商品 SKU12345 库存...
库存服务: 扣减商品 SKU12345 库存 2 件
支付服务: 订单 ORD20240115001 支付 ¥299.0
物流服务: 创建运单 SF1705289123456,收货地址: 北京市朝阳区xxx
通知服务: 发送短信到 13800138000: 您的订单 ORD20240115001 已发货,运单号: SF1705289123456
========== 订单处理完成 ==========

下单成功

📊 类图结构

┌─────────────────────────────────────────────────────────┐
│                       Client                            │
└───────────────────────────┬─────────────────────────────┘
                            │ 只调用外观
                            ▼
                   ┌────────────────┐
                   │     Facade     │
                   │  + operation() │
                   └────────┬───────┘
                            │ 调用子系统
           ┌────────────────┼────────────────┐
           ▼                ▼                ▼
    ┌────────────┐   ┌────────────┐   ┌────────────┐
    │ SubSystemA │   │ SubSystemB │   │ SubSystemC │
    └────────────┘   └────────────┘   └────────────┘

✅ 适用场景

  1. 简化复杂系统:为复杂子系统提供简单入口
  2. 解耦客户端和子系统:客户端不需要知道子系统内部
  3. 分层系统:在层与层之间建立外观
  4. 遗留系统包装:为老系统提供新接口

⚠️ 优缺点

优点:

  • 简化客户端调用
  • 降低耦合度
  • 更好的分层

缺点:

  • 不符合开闭原则(增加功能需要修改外观类)
  • 可能成为"上帝类"

小结

外观模式的核心:为复杂的子系统提供一个简单统一的接口。

简单记忆:外观模式 = 服务台 = 一站式服务

👉 下一篇:享元模式

Prev
装饰器模式 (Decorator)
Next
享元模式 (Flyweight)