外观模式

简介

定义: 提供一个统一的接口,用来访问子系统中的一群接口,外观定义了一个高层的接口,让子系统更容易使用。其实就是为了方便客户的使用,把一群操作,封装成一个方法。

使用场景:

  • 复杂系统的简化接口

  • 分层架构的各层入口

  • 第三方库的封装

  • 微服务网关

实现要点:

  • 封装多个子系统

  • 提供简化的统一接口

  • 最少知识原则

UML

代码示例

  1. 几个子系统

public class Amplifier {
    
    private String description;
    private int volume;
    
    public Amplifier(String description) {
        this.description = description;
        this.volume = 5;
    }
    
    public void on() {
        System.out.println("🔊 " + description + " 功放打开");
    }
    
    public void off() {
        System.out.println("🔇 " + description + " 功放关闭");
    }
    
    public void setVolume(int level) {
        this.volume = level;
        System.out.println("🔊 " + description + " 音量设置为: " + level);
    }
    
    public void setSurroundSound() {
        System.out.println("🔊 " + description + " 环绕立体声模式已开启");
    }
    
    public void setStereoSound() {
        System.out.println("🔊 " + description + " 立体声模式已开启");
    }
    
    public int getVolume() {
        return volume;
    }
}
public class DVDPlayer {
    
    private String description;
    private String currentMovie;
    
    public DVDPlayer(String description) {
        this.description = description;
    }
    
    public void on() {
        System.out.println("📀 " + description + " DVD播放器打开");
    }
    
    public void off() {
        System.out.println("📀 " + description + " DVD播放器关闭");
    }
    
    public void play(String movie) {
        this.currentMovie = movie;
        System.out.println("📀 " + description + " 正在播放: \"" + movie + "\"");
    }
    
    public void pause() {
        System.out.println("⏸️ " + description + " 暂停播放: \"" + currentMovie + "\"");
    }
    
    public void stop() {
        System.out.println("⏹️ " + description + " 停止播放: \"" + currentMovie + "\"");
        currentMovie = null;
    }
    
    public void eject() {
        if (currentMovie != null) {
            System.out.println("⏏️ " + description + " 弹出光盘: \"" + currentMovie + "\"");
            currentMovie = null;
        } else {
            System.out.println("⏏️ " + description + " 弹出光盘");
        }
    }
}
public class PopcornPopper {
    
    private String description;
    
    public PopcornPopper(String description) {
        this.description = description;
    }
    
    public void on() {
        System.out.println("🍿 " + description + " 爆米花机打开");
    }
    
    public void off() {
        System.out.println("🍿 " + description + " 爆米花机关闭");
    }
    
    public void pop() {
        System.out.println("🍿 " + description + " 开始制作爆米花...");
        System.out.println("🍿 爆米花制作完成!");
    }
}
public class Projector {
    
    private String description;
    
    public Projector(String description) {
        this.description = description;
    }
    
    public void on() {
        System.out.println("📽️ " + description + " 投影仪打开");
    }
    
    public void off() {
        System.out.println("📽️ " + description + " 投影仪关闭");
    }
    
    public void wideScreenMode() {
        System.out.println("📽️ " + description + " 设置为宽屏模式 (16:9)");
    }
    
    public void normalMode() {
        System.out.println("📽️ " + description + " 设置为标准模式 (4:3)");
    }
}
public class Screen {
    
    private String description;
    
    public Screen(String description) {
        this.description = description;
    }
    
    public void up() {
        System.out.println("🎬 " + description + " 幕布收起");
    }
    
    public void down() {
        System.out.println("🎬 " + description + " 幕布放下");
    }
}
public class TheaterLights {
    
    private String description;
    private int brightness;
    
    public TheaterLights(String description) {
        this.description = description;
        this.brightness = 100;
    }
    
    public void on() {
        System.out.println("💡 " + description + " 灯光打开");
        this.brightness = 100;
    }
    
    public void off() {
        System.out.println("💡 " + description + " 灯光关闭");
        this.brightness = 0;
    }
    
    public void dim(int level) {
        this.brightness = level;
        System.out.println("💡 " + description + " 灯光调暗至: " + level + "%");
    }
    
    public int getBrightness() {
        return brightness;
    }
}
  1. 外观模式核心类

public class HomeTheaterFacade {
    
    private Amplifier amplifier;
    private DVDPlayer dvdPlayer;
    private Projector projector;
    private TheaterLights lights;
    private Screen screen;
    private PopcornPopper popper;
    
    /**
     * 构造函数 - 注入所有子系统
     */
    public HomeTheaterFacade(Amplifier amplifier,
                            DVDPlayer dvdPlayer,
                            Projector projector,
                            TheaterLights lights,
                            Screen screen,
                            PopcornPopper popper) {
        this.amplifier = amplifier;
        this.dvdPlayer = dvdPlayer;
        this.projector = projector;
        this.lights = lights;
        this.screen = screen;
        this.popper = popper;
    }
    
    /**
     * 观看电影 - 封装了复杂的操作步骤
     */
    public void watchMovie(String movie) {
        System.out.println("\n🎬 ========== 准备观看电影 ==========");
        System.out.println("📺 正在为您准备观影环境...\n");
        
        // 1. 制作爆米花
        popper.on();
        popper.pop();
        
        // 2. 调暗灯光
        lights.dim(10);
        
        // 3. 放下幕布
        screen.down();
        
        // 4. 打开投影仪
        projector.on();
        projector.wideScreenMode();
        
        // 5. 打开功放
        amplifier.on();
        amplifier.setVolume(8);
        amplifier.setSurroundSound();
        
        // 6. 打开DVD播放器并播放电影
        dvdPlayer.on();
        dvdPlayer.play(movie);
        
        System.out.println("\n✅ 准备完成,请尽情享受电影!");
    }
    
    /**
     * 结束电影 - 封装了关闭所有设备的步骤
     */
    public void endMovie() {
        System.out.println("\n🎬 ========== 关闭影院系统 ==========");
        System.out.println("📺 正在关闭所有设备...\n");
        
        // 1. 关闭爆米花机
        popper.off();
        
        // 2. 调亮灯光
        lights.on();
        
        // 3. 收起幕布
        screen.up();
        
        // 4. 关闭投影仪
        projector.off();
        
        // 5. 停止DVD并关闭
        dvdPlayer.stop();
        dvdPlayer.eject();
        dvdPlayer.off();
        
        // 6. 关闭功放
        amplifier.off();
        
        System.out.println("\n✅ 所有设备已关闭,感谢观影!");
    }
    
    /**
     * 暂停电影
     */
    public void pauseMovie() {
        System.out.println("\n⏸️ ========== 暂停电影 ==========");
        dvdPlayer.pause();
        lights.dim(50);
        System.out.println("✅ 电影已暂停,灯光已调亮");
    }
    
    /**
     * 继续电影
     */
    public void resumeMovie(String movie) {
        System.out.println("\n▶️ ========== 继续电影 ==========");
        lights.dim(10);
        dvdPlayer.play(movie);
        System.out.println("✅ 电影继续播放");
    }
    
    /**
     * 调整音量
     */
    public void setVolume(int level) {
        System.out.println("\n🔊 调整音量");
        amplifier.setVolume(level);
    }
    
    /**
     * 调整灯光
     */
    public void setLights(int brightness) {
        System.out.println("\n💡 调整灯光");
        lights.dim(brightness);
    }
}
  1. 使用方式

public class Test {

    public static void main(String[] args) {
        System.out.println("=== 外观模式 - 家庭影院系统示例 ===\n");

        // 创建所有子系统组件
        Amplifier amplifier = new Amplifier("索尼5.1声道");
        DVDPlayer dvdPlayer = new DVDPlayer("索尼蓝光");
        Projector projector = new Projector("爱普生4K");
        TheaterLights lights = new TheaterLights("智能灯光系统");
        Screen screen = new Screen("电动投影幕布");
        PopcornPopper popper = new PopcornPopper("爆米花机");

        // ========== 对比:不使用外观模式 ==========
        System.out.println("【场景1:不使用外观模式 - 手动操作所有设备】");
        System.out.println("客户端需要了解所有子系统的细节,操作复杂:\n");
        
        System.out.println("观影前需要执行以下步骤:");
        System.out.println("1. popper.on()");
        System.out.println("2. popper.pop()");
        System.out.println("3. lights.dim(10)");
        System.out.println("4. screen.down()");
        System.out.println("5. projector.on()");
        System.out.println("6. projector.wideScreenMode()");
        System.out.println("7. amplifier.on()");
        System.out.println("8. amplifier.setVolume(8)");
        System.out.println("9. amplifier.setSurroundSound()");
        System.out.println("10. dvdPlayer.on()");
        System.out.println("11. dvdPlayer.play(movie)");
        System.out.println("\n❌ 太复杂了!容易出错,用户体验差!");

        // ========== 使用外观模式 ==========
        System.out.println("\n\n【场景2:使用外观模式 - 简化操作】");
        System.out.println("客户端只需要调用一个简单的方法:\n");
        
        // 创建外观对象
        HomeTheaterFacade homeTheater = new HomeTheaterFacade(
            amplifier, dvdPlayer, projector, lights, screen, popper
        );

        // 测试1:观看电影
        homeTheater.watchMovie("阿凡达2:水之道");

        // 模拟观影过程
        System.out.println("\n⏳ 电影播放中...");
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        // 测试2:暂停电影
        homeTheater.pauseMovie();

        // 模拟暂停时间
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        // 测试3:继续电影
        homeTheater.resumeMovie("阿凡达2:水之道");

        // 模拟继续观影
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        // 测试4:调整音量
        homeTheater.setVolume(12);

        // 测试5:调整灯光
        homeTheater.setLights(20);

        // 模拟观影结束
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        // 测试6:结束电影
        homeTheater.endMovie();

        System.out.println("\n\n=== 外观模式说明 ===");
        System.out.println("1. 子系统: Amplifier、DVDPlayer等 - 各自独立的复杂系统");
        System.out.println("2. 外观类: HomeTheaterFacade - 提供简化的统一接口");
        System.out.println("3. 客户端: 只需要与外观类交互,无需了解子系统细节");
        System.out.println("4. 封装性: 将复杂的操作序列封装在外观类中");

        System.out.println("\n=== 外观模式优势 ===");
        System.out.println("✅ 简化接口: 为复杂子系统提供简单接口");
        System.out.println("✅ 降低耦合: 客户端与子系统解耦");
        System.out.println("✅ 提高可用性: 用户无需了解系统内部结构");
        System.out.println("✅ 更好的分层: 定义系统中每层的入口点");
        System.out.println("✅ 灵活性: 客户端仍可直接访问子系统");

        System.out.println("\n=== 外观模式应用场景 ===");
        System.out.println("📌 复杂系统简化: 为复杂系统提供简单入口");
        System.out.println("📌 分层架构: 定义各层之间的接口");
        System.out.println("📌 遗留系统封装: 为老旧系统提供新接口");
        System.out.println("📌 第三方库封装: 简化第三方API使用");
        System.out.println("📌 微服务网关: API网关就是外观模式");

        System.out.println("\n=== 外观模式 vs 适配器模式 ===");
        System.out.println("外观模式: 简化接口,封装多个子系统");
        System.out.println("适配器模式: 转换接口,让不兼容的接口协同工作");

        System.out.println("\n=== 外观模式的最佳实践 ===");
        System.out.println("✨ 最少知识原则: 客户端只与外观类交互");
        System.out.println("✨ 保留灵活性: 仍允许直接访问子系统");
        System.out.println("✨ 职责单一: 外观类只负责协调子系统");
        System.out.println("✨ 可扩展性: 易于添加新的外观方法");
    }
}

Last updated

Was this helpful?