美文网首页设计模式系列教程
设计模式系列教程—Facade Pattern(外观模式)

设计模式系列教程—Facade Pattern(外观模式)

作者: Vander1991 | 来源:发表于2019-05-14 21:59 被阅读0次

8 Facade Pattern(外观模式)

前言:让接口变得简单。
例子说明:
REQ1:还记得之前学习过的命令模式吗,后面提出了开启所有相关家电的命令,和关闭所有家电的命令,但是的目的就是为了可以一键进行一系列家电的操作,在这里也类似。
Vander之前刚完成了上个设计,赚了很多钱,现在它入手了一整套小米装备,有小米音响、小米空调、小米空气净化器、小米爆米花机、小米投影仪、小米投影幕布,它想在家里开影院,制造一个良好的氛围来好好享受这个周末。有以下这些家电:

image.png

分析:先来看看类图,Vander发现买了一堆设备,花了一大堆时间终于把这些设备连接起来了,接下来要开启这些设备,想看一部电影需要完成:
1、打开影院灯,调节成dim
2、打开空气净化器
3、放下屏幕
4、打开投影
5、将投影的输入切换到dvd
6、设置投影成宽屏模式
7、打开功放
8、功放的输入为dvd
9、调节功放音量
10、开启dvd
11、播放dvd
涉及到如此多的类,看完电影之后还要一个个关掉,这才头疼,Vander心想:想过个心情愉悦的周末就这么难吗?将所有的步骤写在一起,按照一定的顺序,让一个总控来帮我完成这些事情。然后Vander定义了一个家庭影院外观(HomeTheaterFacade)。


image.png

分析:外观模式允许我们让客户和子系统之间避免紧耦合。
外观模式:提供一个统一的接口,用来访问子系统中的一群接口。外观定义了一个高层接口,让子系统更容易使用。
这个模式可以通过实现一个提供更合理的接口的外观类,可以将一个复杂的子系统变得容易使用。外观模式不只是简化了接口,也将客户从组件的子系统中解耦。
外观模式和适配器模式比较:
1、外观和适配器都可以包装许多类
2、外观的意图是简化接口
3、适配器的意图是将接口转成所需的接口
下面是模式的一般类图:

image.png

适配器模式很好地运用了OO的设计原则,使用对象组合,以修改的接口包装被适配者。0
影院对象:

public class HomeTheaterFacade {

    private Amplifier amp;
    
    private DvdPlayer dvd;
    
    private AirCondition airCondition;
    
    private Projector projector;
    
    private Screen screen;
    
    private TheaterLight theaterLight;
    
    private Television television;

    public HomeTheaterFacade(Amplifier amp, DvdPlayer dvd, AirCondition airCondition, Projector projector,
            Screen screen, TheaterLight theaterLight, Television television) {
        super();
        this.amp = amp;
        this.dvd = dvd;
        this.airCondition = airCondition;
        this.projector = projector;
        this.screen = screen;
        this.theaterLight = theaterLight;
        this.television = television;
    }
    
    public void watchMoive(String moive) {
        theaterLight.on();
        theaterLight.dim();
        screen.down();
        airCondition.on();
        projector.on();
        projector.wideScreenMode();
        amp.on();
        amp.setDvdPlayer(dvd);
        dvd.setAmplifier(amp);
        dvd.on();
        dvd.setVolume(10);
        dvd.play(moive);
    }
    
    public void endMoive() {
        screen.up();
        airCondition.off();
        projector.off();
        amp.off();
        dvd.off();
        theaterLight.off();
    }
    
    public void watchTv() {
        theaterLight.on();
        airCondition.on();
        amp.on();
        amp.setTelevision(television);
        television.on();
    }
    
    public void closeTv() {
        television.off();
        theaterLight.off();
        airCondition.off();
        amp.off();
    }
    
}

音响:

public class Amplifier {

    private DvdPlayer dvdPlayer;

    private Television television;
    
    private int volume;
    
    public void on() {
        System.out.println("Open Amplifier!");
    }
    
    public void off() {
        System.out.println("Close Amplifier!");
    }
    
    public void setVolume(int volume) {
        this.volume = volume;
    }
    
    public void setDvdPlayer(DvdPlayer dvdPlayer) {
        this.dvdPlayer = dvdPlayer;
    }

    public void setTelevision(Television television) {
        this.television = television;
    }
    
    public void play() {
        if(this.dvdPlayer != null) {
            System.out.println("Connect Dvd Player");
        } else if(this.television != null ) {
            System.out.println("Connect Television");
        } else {
            System.out.println("Connect Nothing");
        }
        System.out.println("Amplifier is" + this.volume);
    }
    
}

实现的效果:


image.png

其余的类都比较类似,这里不一一列举了,这里只是为了说明HomeTheaterFacade提供了一个简化的接口,让用户调用起来非常方便。
有了外观模式最大的好处是减少了客户跟子系统之间的紧密耦合,外观模式帮我们很好地实现了一个原则——最小知识原则(Law of Demeter[墨忒耳法则])。

最小知识原则——只和你的密友谈话。

意思是在设计一个系统的时候不管是任何对象都要注意它所交互的类有哪些,注意它和这些类是如何交互的。这个原则希望我们在设计中不要让太多的类耦合在一起,免得修改系统中的一部分会影响到其他部分。如果许多类之间相互依赖,那么这个系统就是一个易碎的系统。

遵循这个原则,我们对象设计中,该对象方法里只应该调用属于以下范围的方法:
1、该对象本身
2、被当做方法的参数而传递进来的对象
3、此方法所创建或实例化的任何对象
4、对象的任何组件
前三条告诉我们,如果某对象是调用其他的方法的返回结果,不要调用该对象的方法。
第4条告诉我们装配进来的可以调用。

EXP:

    public float getTemp(){
        //先拿到温度计对象,再拿到温度
        Thermometer thermometer = station.getThermometer();
        return thermometer.getTemperature();
    }
    
    public float getTemp(){
        //在气象站中加入方法,直接拿到温度计对象
        return station.getTemperature();
    }

很显然,第二种方法更具有优势,getTemp方法所涉及到的类就少了一个。
举例说明以上四种范围的方法能够被调用的情景:
EXP:

image.png

为了加深对这个原则的理解,下面再看两段代码:
House1:

public class House1 {

    WeatherStation station;
    
    public float getTemp() {
        return station.getThermometer().getTemperature();
    }
    
}

House1明显违反了最少知识原则,因为它调用的方法属于第一次调用返回的对象。
House2:

public class House2 {

    WeatherStation station;
    
    public float getTemp() {
        Thermometer thermometer = station.getThermometer();
        return getTempHelper(thermometer);
    }

    private float getTempHelper(Thermometer thermometer) {
        return thermometer.getTemperature();
    }
    
}

House2虽然没有违反最小知识原则,但是只是为了形式上不违反规则而这么写,所以这样并没有意义。
缺点:最小知识原则虽然减少了对象之间的依赖,也减少了软件的维护成本,但是采用这个原则也会导致更多的“包装”类,以处理和其他组件的沟通,这可能会导致复杂度和开发时间的增加,并降低运行时的性能。

最后又到了喜闻乐见的总结部分,我们又来总结我们现在现有的设计模式武器。

面向对象基础

抽象、封装、多态、继承

六大设计原则

设计原则一:封装变化
设计原则二:针对接口编程,不针对实现编程。
设计原则三:多用组合,少用继承。
设计原则四:为交互对象之间的松耦合设计而努力
设计原则五:对扩展开放,对修改关闭
设计原则六:依赖抽象,不要依赖于具体的类
设计原则七:只和你的密友谈话

模式

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

相关文章

网友评论

    本文标题:设计模式系列教程—Facade Pattern(外观模式)

    本文链接:https://www.haomeiwen.com/subject/qtryaqtx.html