JavaDog程序狗
发布于 2026-11-11 / 2 阅读
0
0

【设计模式】跟着狗哥复习设计模式(十):外观模式

家里有投影仪、幕布、音响和灯光,单看哪个都不复杂。

真准备看电影时,就得挨个操作。漏了音响,画面出来了却没声;忘了关灯,屏幕又灰蒙蒙的。

外观模式干的活挺朴素:把一串常用操作,收进一个简单入口。

加瓦狗一键开启家庭影院

手动开影院,要记不少步骤

不用外观模式,客户端得自己认识每台设备。

它还得记住什么时候关灯、什么时候放幕布、什么时候开音响。

手动开启家庭影院需要记住多个步骤

这段代码并不难,但会散落在按钮、手机页面等地方。以后开机顺序一改,好几处都得跟着动。

济南话说,怪麻烦来。

先看关键 UML 图

外观模式的类图很直白。

外观模式关键 UML 类图

客户端只和 HomeTheaterFacade 打交道。

外观类内部持有投影仪、幕布、音响和灯光,再按照固定顺序调用它们。

底下这些设备类,通常叫子系统。

设备类各忙各的

投影仪只负责开机、播放和关机。

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

    public void play() {
        System.out.println("投影仪开始播放");
    }

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

音响也只管自己的操作。

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

    public void setVolume(int volume) {
        System.out.println("音量调到 " + volume);
    }

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

幕布和灯光的代码也差不多,这里先不整段贴了。它们还是普通类,不需要实现统一接口。

外观类把设备接到一起

HomeTheaterFacade 保存这些设备。

public class HomeTheaterFacade {
    private final Projector projector;
    private final Screen screen;
    private final SoundSystem sound;
    private final RoomLight light;

    public HomeTheaterFacade(Projector projector, Screen screen,
                             SoundSystem sound, RoomLight light) {
        this.projector = projector;
        this.screen = screen;
        this.sound = sound;
        this.light = light;
    }
}

外观类没有替设备干活,它只是知道该找谁、按什么顺序找。

客户端通过外观类操作多个家庭影院设备

一个方法开启电影

开场步骤全放进 watchMovie()。

public void watchMovie() {
    light.dim();
    screen.down();
    projector.on();
    sound.on();
    sound.setVolume(20);
    projector.play();
}

电影结束,也给它一个固定的收尾顺序。

public void endMovie() {
    projector.off();
    sound.off();
    screen.up();
    light.on();
}

外观类统一管理家庭影院的开始和结束顺序

顺序只保留一份。以后想先开音响再开投影仪,改外观类就行。

调用时就省心了

准备好设备,再把它们交给外观类。

HomeTheaterFacade theater = new HomeTheaterFacade(
        new Projector(), new Screen(),
        new SoundSystem(), new RoomLight());

theater.watchMovie();

输出:

灯光调暗
幕布放下
投影仪打开
音响打开
音量调到 20
投影仪开始播放

客户端只调用一次,外观类在里面把活分给各台设备。

青岛话说,这么用挺恣儿,不用抱着四个遥控器来回摁。

有了外观,还能直接操作设备吗

可以。

外观类提供的是方便入口,并没有把子系统锁起来。真有特殊需求,客户端仍然能直接调用投影仪。

客户端既能使用外观类也能直接访问设备

比如只想测试投影仪,不需要启动整套影院,直接调用 projector.on() 更合适。

外观模式帮你省步骤,但不该把简单问题绕复杂。

外观模式和适配器别弄混

适配器解决的是接口对不上,它要把一种接口转换成另一种接口。

外观模式面对的接口本来都能用,只是数量多、步骤杂。它给这些接口再提供一个好用的入口。

一个偏“转换”,一个偏“简化”。看目的,比看类长得像不像更准。

啥时候适合用外观模式

当子系统类比较多,调用流程又相对固定,可以考虑加一层外观。

什么时候适合使用外观模式

支付流程、文件导出、家庭影院,都能用这个思路理解。

不过外观类也不能啥都管。方法越塞越多,它自己就会变成一个大杂烩,到时候照样难维护。

狗哥收个尾

外观模式的重点,是 给复杂子系统提供一个简单入口。

设备类继续各管各的,HomeTheaterFacade 负责协调常用流程。客户端少记步骤,开关顺序也只维护一份。

下一篇继续聊 享元模式。咱看看游戏里一大片树,怎么少创建点对象、少占点内存。


评论