《HeadFirst设计模式》读书笔记-第7章v2-外观模式

定义

外观模式(facade pattern)提供了一个统一的接口,用来访问子系统中的一群接口。外观定义了一个高层接口,让子系统更加容易使用。

这里写图片描述

从上面的图可以看出,Facade类对子系统进行了一下封装,客户只需要和Facade类打交道,不需要接触子系统中的各个类,也不需要了解子系统中各个类间的关系。从这个角度来说,客户也就与子系统解耦了,不需要依赖于子系统中具体的类了。

外观模式的一个重要的目的就是简化系统,提供给客户一个简单的接口,方便客户使用。

代码实现

例子是为家庭影院构造外观,让观看电影的步骤尽可能地简单。下图给出了类图。

这里写图片描述

首先看看HomeTheaterFacade这个高层接口,它提供了6个接口分别执行6个动作,每个动作是通过调用子系统中其它的类来实现的。

public class HomeTheaterFacade {
    Amplifier amp; // 功放
    Tuner tuner; // 电子调音器
    DvdPlayer dvd; //
    CdPlayer cd; //
    Projector projector; // 投影机
    TheaterLights lights; // 剧场灯光
    Screen screen; // 屏幕
    PopcornPopper popper; // 爆米花机

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

    // 开始观看名为“movie”的电影接口
    public void watchMovie(String movie) {
        System.out.println("Get ready to watch a movie...");
        popper.on(); // 打开爆米花机
        popper.pop(); // 开始爆米花
        lights.dim(10); // 调低灯光亮度为10%
        screen.down(); // 放下屏幕
        projector.on(); // 打开投影机
        projector.wideScreenMode(); // 设置宽屏模式
        amp.on(); // 打开功放
        amp.setDvd(dvd); 
        amp.setSurroundSound(); // 设置环绕立体声
        amp.setVolume(5); // 设置音量
        dvd.on();  // 打开DVD播放器
        dvd.play(movie); // 开始播放电影
    }

    public void endMovie() {
        System.out.println("Shutting movie theater down...");
        popper.off();
        lights.on();
        screen.up();
        projector.off();
        amp.off();
        dvd.stop();
        dvd.eject(); // 弹出Dvd播放器
        dvd.off();
    }

    public void listenToCd(String cdTitle) {
        System.out.println("Get ready for an audiopile experence...");
        lights.on();
        amp.on();
        amp.setVolume(5);
        amp.setCd(cd);
        amp.setStereoSound();
        cd.on();
        cd.play(cdTitle);
    }

    public void endCd() {
        System.out.println("Shutting down CD...");
        amp.off();
        amp.setCd(cd);
        cd.eject();
        cd.off();
    }

    public void listenToRadio(double frequency) {
        System.out.println("Tuning in the airwaves...");
        tuner.on();
        tuner.setFrequency(frequency);
        amp.on();
        amp.setVolume(5);
        amp.setTuner(tuner);
    }

    public void endRadio() {
        System.out.println("Shutting down the tuner...");
        tuner.off();
        amp.off();
    }
}

因为子系统中类太多了,这里只列出几个,其它的类似,不影响理解模式。

Amplifier.java

public class Amplifier {
    String description;
    Tuner tuner;
    DvdPlayer dvd;
    CdPlayer cd;

    public Amplifier(String description) {
        this.description = description;
    }

    public void on() {
        System.out.println(description + " on");
    }

    public void off() {
        System.out.println(description + " off");
    }

    public void setStereoSound() {
        System.out.println(description + " stereo mode on");
    }

    public void setSurroundSound() {
        System.out.println(description + " surround sound on (5 speakers, 1 subwoofer)");
    }

    public void setVolume(int level) {
        System.out.println(description + " setting volume to " + level);
    }

    public void setTuner(Tuner tuner) {
        System.out.println(description + " setting tuner to " + dvd);
        this.tuner = tuner;
    }

    public void setDvd(DvdPlayer dvd) {
        System.out.println(description + " setting DVD player to " + dvd);
        this.dvd = dvd;
    }

    public void setCd(CdPlayer cd) {
        System.out.println(description + " setting CD player to " + cd);
        this.cd = cd;
    }

    public String toString() {
        return description;
    }
}

CdPlayer.java

public class CdPlayer {
    String description;
    int currentTrack;
    Amplifier amplifier;
    String title;

    public CdPlayer(String description, Amplifier amplifier) {
        this.description = description;
        this.amplifier = amplifier;
    }

    public void on() {
        System.out.println(description + " on");
    }

    public void off() {
        System.out.println(description + " off");
    }

    public void eject() {
        title = null;
        System.out.println(description + " eject");
    }

    public void play(String title) {
        this.title = title;
        currentTrack = 0;
        System.out.println(description + " playing \"" + title + "\"");
    }

    public void play(int track) {
        if (title == null) {
            System.out.println(description + " can't play track " + currentTrack + 
                    ", no cd inserted");
        } else {
            currentTrack = track;
            System.out.println(description + " playing track " + currentTrack);
        }
    }

    public void stop() {
        currentTrack = 0;
        System.out.println(description + " stopped");
    }

    public void pause() {
        System.out.println(description + " paused \"" + title + "\"");
    }

    public String toString() {
        return description;
    }
}

Screen.java

public class Screen {
    String description;

    public Screen(String description) {
        this.description = description;
    }

    public void up() {
        System.out.println(description + " going up");
    }

    public void down() {
        System.out.println(description + " going down");
    }

    public String toString() {
        return description;
    }
}

测试驱动代码,也是客户代码:

public class HomeTheaterTestDrive {
    public static void main(String[] args) {
        Amplifier amp = new Amplifier("Top-O-Line Amplifier");
        Tuner tuner = new Tuner("Top-O-Line AM/FM Tuner", amp);
        DvdPlayer dvd = new DvdPlayer("Top-O-Line DVD Player", amp);
        CdPlayer cd = new CdPlayer("Top-O-Line CD Player", amp);
        Projector projector = new Projector("Top-O-Line Projector", dvd);
        TheaterLights lights = new TheaterLights("Theater Ceiling Lights");
        Screen screen = new Screen("Theater Screen");
        PopcornPopper popper = new PopcornPopper("Popcorn Popper");

        HomeTheaterFacade homeTheater = 
                new HomeTheaterFacade(amp, tuner, dvd, cd, 
                        projector, screen, lights, popper);
        // 客户开始/停止看电影只要调用高层接口的Api即可
        // 不需要和子系统中其它类交互
        homeTheater.watchMovie("Raiders of the Lost Ark");
        homeTheater.endMovie();
    }
}

该模式体现了哪些OO原则

  1. 原则3: 多用组合,少用继承

    HomeTheaterFacade组合了子系统中各个对象,来实现对客户来说更加友好对接口。

  2. 原则7: 最少知识原则

    客户代码只要调用HomeTheaterFacade的方法,只依赖于它。不管子系统内部实现怎么变化,只要HomeTheaterFacade的接口没有变化,客户代码就不需要变化。

本章总结

  1. 外观模式不只是简化了子系统的接口,也将客户从组件的子系统中解耦

  2. 外观只是对子系统的接口进行了更高层次的抽象,客户还是可以直接调用子系统中的类的,当然一般情况这是不必要的,只要外观接口定义的好

  3. 外观模式符合“最少知识原则”

  4. 适配器模式和外观模式的差别:

    两种模式都是对其它的接口的再次封装。差别在适配器强调对一个或者多个接口的转换,而外观模式则强调简化接口

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值