Head First 外观模式

20 阅读2分钟

一、定义

外观模式: 提供了一个统一的接口,用来访问子系统中的一群接口。外观定义了一个高层接口,让子系统更容易使用。
这个定义清楚的告诉我们,外观的意图是要提供一个简单的接口,好让一个子系统更易于使用。从这个模式的类图可以感受到这一点。

facade.png

相关代码如下:

public class Amplifier {

    public void on() {
        System.out.println("Amplifier on");
    }
    public void setDvd(DvdPlayer dvd) {
        System.out.println("Amplifier setDvd");
    }

    public void setSurroundSound() {
        System.out.println("Amplifier setSurroundSound");
    }

    public void setVolume(int volume) {
        System.out.println("Amplifier setVolume");
    }

    public void off() {
        System.out.println("Amplifier off");
    }
}
public class CdPlayer {
// 有一些方法
}
public class DvdPlayer {
// 有一些方法
}
public class PopcornPopper {
// 有一些方法
}
public class Projector {
// 有一些方法
}
public class Screen {
// 有一些方法
}

/**
 * 外观
 */
public class HomeTheaterFacade {

    private Amplifier amplifier;

    private Tuner tuner;

    private DvdPlayer dvdPlayer;

    private CdPlayer cdPlayer;

    private PopcornPopper popper;

    private Screen screen;

    private TheaterLights lights;

    private Projector projector;

    public HomeTheaterFacade(Amplifier amplifier, Tuner tuner, DvdPlayer dvdPlayer, CdPlayer cdPlayer, PopcornPopper popper, Screen screen, TheaterLights lights, Projector projector) {
        this.amplifier = amplifier;
        this.tuner = tuner;
        this.dvdPlayer = dvdPlayer;
        this.cdPlayer = cdPlayer;
        this.popper = popper;
        this.screen = screen;
        this.lights = lights;
        this.projector = projector;
    }

    public void watchMovie(String movie) {
        System.out.println("get ready to watch a movie: " + movie);
        popper.on();
        popper.pop();
        lights.dim(10);
        screen.down();
        projector.on();
        projector.wideScreenMode();
        amplifier.on();
        amplifier.setDvd(dvdPlayer);
        amplifier.setSurroundSound();
        amplifier.setVolume(11);
        dvdPlayer.on();
        dvdPlayer.play(movie);
    }

    public void endMovie() {
        System.out.println("Shutting movie theater down");
        popper.off();
        lights.on();
        screen.up();
        projector.off();
        amplifier.off();
        dvdPlayer.stop();
        dvdPlayer.eject();
        dvdPlayer.off();
    }
}

/**
 * 测试类
 */
public class HomeTheaterTest {

    public static void main(String[] args) {
        Amplifier amplifier = new Amplifier();
        Tuner tuner = new Tuner();
        Projector projector = new Projector();
        Screen screen = new Screen();
        PopcornPopper popper = new PopcornPopper();
        TheaterLights theaterLights = new TheaterLights();
        DvdPlayer dvdPlayer = new DvdPlayer();
        CdPlayer cdPlayer = new CdPlayer();
        HomeTheaterFacade facade = new HomeTheaterFacade(amplifier, tuner, dvdPlayer, cdPlayer, popper, screen, theaterLights, projector);
        facade.watchMovie("音乐之声");
        facade.endMovie();
    }
}

使用到的设计原则

  • 最少知识原则

多种模式之间的对比

二、总结要点

  • 当需要简化并统一一个很大的接口或者一群复杂的接口时,使用外观模式。
  • 外观模式将客户从一个复杂的子系统中解耦。
  • 实现一个外观,需要将子系统组合进外观中,然后将工作委托给子系统执行。
  • 你可以为一个子系统实现多个外观。
  • 通常来讲,仅需要一个外观对象,因此Facade对象通常属于单例模式。

三、应用场景

  • Java日志门面(SLF4J):SLF4J(Simple Logging Facade for Java)是一个日志门面框架,它提供了一组统一的日志API(如org.slf4j.Logger),客户端代码只需依赖SLF4J接口,而无需关心底层具体日志实现(如Logback、Log4j等)。‌‌