Skip to content

外观模式

基础概念

什么是外观模式?

答案: 外观模式(Facade Pattern)为子系统中的一组接口提供一个统一的高层接口,使得子系统更容易使用。

使用场景

  • 为复杂子系统提供简单接口
  • 客户端与多个子系统有依赖
  • 构建分层系统

优点

  • 简化接口
  • 解耦客户端和子系统
  • 更好的分层

缺点

  • 不符合开闭原则
  • 增加外观类

实现方式

基本实现?

答案:

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 systemA;
    private SubSystemB systemB;
    private SubSystemC systemC;

    public Facade() {
        this.systemA = new SubSystemA();
        this.systemB = new SubSystemB();
        this.systemC = new SubSystemC();
    }

    public void operation() {
        systemA.operationA();
        systemB.operationB();
        systemC.operationC();
    }
}

// 使用
Facade facade = new Facade();
facade.operation();

实际应用

家庭影院系统

答案:

java
// 投影仪
public class Projector {
    public void on() {
        System.out.println("投影仪打开");
    }

    public void off() {
        System.out.println("投影仪关闭");
    }
}

// 音响
public class Stereo {
    public void on() {
        System.out.println("音响打开");
    }

    public void setVolume(int volume) {
        System.out.println("音量设置为: " + volume);
    }

    public void off() {
        System.out.println("音响关闭");
    }
}

// DVD播放器
public class DVDPlayer {
    public void on() {
        System.out.println("DVD播放器打开");
    }

    public void play(String movie) {
        System.out.println("播放电影: " + movie);
    }

    public void off() {
        System.out.println("DVD播放器关闭");
    }
}

// 灯光
public class Light {
    public void dim(int level) {
        System.out.println("灯光调暗至: " + level + "%");
    }

    public void on() {
        System.out.println("灯光打开");
    }
}

// 家庭影院外观
public class HomeTheaterFacade {
    private Projector projector;
    private Stereo stereo;
    private DVDPlayer dvdPlayer;
    private Light light;

    public HomeTheaterFacade() {
        this.projector = new Projector();
        this.stereo = new Stereo();
        this.dvdPlayer = new DVDPlayer();
        this.light = new Light();
    }

    public void watchMovie(String movie) {
        System.out.println("准备观看电影...");
        light.dim(10);
        projector.on();
        stereo.on();
        stereo.setVolume(20);
        dvdPlayer.on();
        dvdPlayer.play(movie);
    }

    public void endMovie() {
        System.out.println("关闭影院...");
        dvdPlayer.off();
        stereo.off();
        projector.off();
        light.on();
    }
}

// 使用
HomeTheaterFacade homeTheater = new HomeTheaterFacade();
homeTheater.watchMovie("阿凡达");
homeTheater.endMovie();

电商下单系统

答案:

java
// 库存系统
public class InventoryService {
    public boolean checkStock(Long productId, int quantity) {
        System.out.println("检查库存");
        return true;
    }

    public void lockStock(Long productId, int quantity) {
        System.out.println("锁定库存");
    }
}

// 支付系统
public class PaymentService {
    public boolean pay(Long orderId, BigDecimal amount) {
        System.out.println("处理支付");
        return true;
    }
}

// 物流系统
public class LogisticsService {
    public void createShipment(Long orderId) {
        System.out.println("创建物流单");
    }
}

// 通知系统
public class NotificationService {
    public void sendOrderNotification(Long orderId) {
        System.out.println("发送订单通知");
    }
}

// 订单外观
public class OrderFacade {
    private InventoryService inventoryService;
    private PaymentService paymentService;
    private LogisticsService logisticsService;
    private NotificationService notificationService;

    public OrderFacade() {
        this.inventoryService = new InventoryService();
        this.paymentService = new PaymentService();
        this.logisticsService = new LogisticsService();
        this.notificationService = new NotificationService();
    }

    public boolean createOrder(Long productId, int quantity, BigDecimal amount) {
        // 1. 检查库存
        if (!inventoryService.checkStock(productId, quantity)) {
            return false;
        }

        // 2. 锁定库存
        inventoryService.lockStock(productId, quantity);

        // 3. 处理支付
        Long orderId = 123L;
        if (!paymentService.pay(orderId, amount)) {
            return false;
        }

        // 4. 创建物流
        logisticsService.createShipment(orderId);

        // 5. 发送通知
        notificationService.sendOrderNotification(orderId);

        return true;
    }
}

// 使用
OrderFacade orderFacade = new OrderFacade();
boolean success = orderFacade.createOrder(1L, 2, new BigDecimal("100.00"));

Spring中的外观模式

JdbcTemplate?

答案:

java
// JdbcTemplate是外观模式的应用
@Autowired
private JdbcTemplate jdbcTemplate;

// 简化了JDBC的复杂操作
public User getUser(Long id) {
    return jdbcTemplate.queryForObject(
        "SELECT * FROM user WHERE id = ?",
        new BeanPropertyRowMapper<>(User.class),
        id
    );
}

// 内部封装了:
// 1. 获取连接
// 2. 创建Statement
// 3. 执行SQL
// 4. 处理结果集
// 5. 关闭资源
// 6. 异常处理

练习题

  1. 外观模式和适配器模式的区别?
  2. 外观模式和代理模式的区别?
  3. 什么时候使用外观模式?
  4. 外观模式如何体现迪米特法则?
  5. 如何避免外观类过于庞大?

Released under the MIT License.