外观模式(Facade Pattern)

外观模式是 23 种设计模式中的一种结构型模式,其核心思想是为复杂系统中的一组接口提供一个统一的高层接口,使子系统更易于使用。这种模式通过引入一个 “外观类”,封装子系统的复杂性,为客户端提供简单直观的访问入口,从而降低客户端与子系统之间的耦合度。

核心原理

外观角色(Facade):
提供一个统一的接口,封装子系统的复杂交互逻辑
客户端通过外观类访问子系统,无需直接与子系统交互
子系统角色(Subsystem):
由多个相关联的类组成,实现子系统的具体功能
对子系统而言,外观类只是另一个客户端,不影响子系统内部结构
客户端(Client):
通过外观类与子系统交互,无需了解子系统的内部实现
简化了与复杂系统的交互过程

外观模式的核心是 “封装复杂性,提供简化接口”,遵循 “最少知识原则”(迪米特原则),减少客户端需要了解的类和方法数量。

Java 实践示例

以 “家庭影院系统” 为例实现外观模式:
家庭影院包含多个设备(投影仪、音响、播放器、灯光等)
观看电影需要协调多个设备的操作(开投影仪、开音响、关灯光等)
外观类封装这些复杂操作,提供 “一键观影” 的简化接口

package com.example.demo;

public class FacadePattern {
    public static void main(String[] args) {
        // 创建子系统组件
        Projector projector = new Projector();
        SoundSystem soundSystem = new SoundSystem();
        Player player = new Player();
        Light light = new Light();

        // 创建外观类
        HomeTheaterFacade theaterFacade = new HomeTheaterFacade(
                projector, soundSystem, player, light
        );

        System.out.println("=== 准备观看电影 ===");
        theaterFacade.watchMovie("星际穿越");

        System.out.println("\n=== 电影结束 ===");
        theaterFacade.endMovie();
    }

    // 子系统:投影仪
    public static class Projector {
        public void on() {
            System.out.println("投影仪已开启");
        }

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

        public void setInput(String source) {
            System.out.println("投影仪输入源设置为:" + source);
        }

        public void zoomIn() {
            System.out.println("投影仪画面放大");
        }
    }

    // 子系统:音响系统
    public static class SoundSystem {
        public void on() {
            System.out.println("音响系统已开启");
        }

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

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

    // 子系统:播放器
    public static class Player {
        public void on() {
            System.out.println("播放器已开启");
        }

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

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

        public void stop() {
            System.out.println("电影播放已停止");
        }
    }

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

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

    // 外观类:家庭影院外观
    public static class HomeTheaterFacade {
        // 持有子系统组件的引用
        private Projector projector;
        private SoundSystem soundSystem;
        private Player player;
        private Light light;

        // 通过构造函数注入子系统组件
        public HomeTheaterFacade(Projector projector, SoundSystem soundSystem,
                                 Player player, Light light) {
            this.projector = projector;
            this.soundSystem = soundSystem;
            this.player = player;
            this.light = light;
        }

        // 封装观看电影的复杂流程
        public void watchMovie(String movie) {
            System.out.println("准备观看电影...");
            light.dim(20);          // 调暗灯光
            projector.on();         // 打开投影仪
            projector.setInput("播放器"); // 设置输入源
            projector.zoomIn();     // 放大画面
            soundSystem.on();       // 打开音响
            soundSystem.setVolume(8); // 设置音量
            player.on();            // 打开播放器
            player.play(movie);     // 播放电影
        }

        // 封装结束电影的复杂流程
        public void endMovie() {
            System.out.println("结束电影...");
            light.on();             // 打开灯光
            projector.off();        // 关闭投影仪
            soundSystem.off();      // 关闭音响
            player.stop();          // 停止播放
            player.off();           // 关闭播放器
        }
    }
    //=== 准备观看电影 ===
    //准备观看电影...
    //灯光调暗至:20%
    //投影仪已开启
    //投影仪输入源设置为:播放器
    //投影仪画面放大
    //音响系统已开启
    //音响音量设置为:8
    //播放器已开启
    //正在播放电影:星际穿越
    //
    //=== 电影结束 ===
    //结束电影...
    //灯光已打开
    //投影仪已关闭
    //音响系统已关闭
    //电影播放已停止
    //播放器已关闭
}

外观模式的特点

优点:
简化接口:为复杂子系统提供简单统一的访问接口,降低使用难度
解耦客户端与子系统:客户端无需了解子系统内部结构,减少耦合
提高灵活性:子系统内部变化时,只需调整外观类,不影响客户端
符合迪米特原则:客户端只需与外观类交互,减少与其他类的通信
缺点:
外观类可能成为 “上帝对象”,承担过多职责
新增子系统功能时,可能需要修改外观类,违反开闭原则
与适配器模式的区别:
外观模式:为复杂系统提供简化接口,不改变原有接口
适配器模式:将一个接口转换为另一个接口,解决接口不兼容问题

外观模式的应用场景

复杂系统简化:
当系统包含多个子模块,且模块间交互复杂时
例如:电商平台的下单流程(涉及库存、支付、物流等子系统)
框架封装:
框架为开发者提供简化接口,隐藏内部实现细节
例如:Spring 的JdbcTemplate封装了复杂的 JDBC 操作
例如:MyBatis 的SqlSession封装了数据库访问的复杂逻辑
遗留系统集成:
为老旧系统提供新的外观接口,便于与新系统集成
避免直接修改遗留系统代码,降低风险
分层架构中的层间交互:
在分层架构中,每层可为上层提供外观接口
例如:服务层为控制层提供外观接口,封装多个 DAO 的交互

外观模式是 “封装复杂性” 的典型实现,在框架设计和系统集成中应用广泛。它通过提供简洁接口,降低了系统的使用门槛,同时隔离了客户端与子系统的直接依赖,提高了系统的可维护性。

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐