设计之禅——外观模式

2020-09-07 10:45:20 浏览数 (1)

概述

平时在我们生活中,我们常常会接触学习各种各样的新事物,而能够快速吸引留住大量客户的都有一个共性,就是简单易学好上手。比如,windows和linux系统,前者比后者更加普及的原因也就是不需要经过专业系统的学习就能轻松使用。同样的,这种思想在编程界有一个专业的术语——外观模式。

定义

首先我们来看看它的定义:

外观模式定义了一个统一的接口,用来访问子系统中的一群接口,使得子系统更容易使用。

概念比较简单,也很容易懂,不过还是有些抽象,下面我通过一个例子来具体讲讲:想象一下你刚住进你的新家,如你所想的布置了 一套家庭影院系统(投屏、音箱、灯光等)。当你下班回家时,你想先泡个澡,然后开启家庭影院系统,享受惬意的生活。但是,每次回去你都得一个个的将浴缸水放上,打开灯、电视等,之后又得一个个关上,这样繁杂的操作反而会令人感到烦躁。而外观模式的作用就是他提供给你一个统一的操作按钮(比如叫影院模式),你只需要按下这一个按钮上述的家居就都自动开始工作了,看完之后再按下统一的关闭按钮就行,这样我们就能更加的惬意地享受下班生活了(PS:我之前写过一篇关于命令模式的文章,里面有一个关于命令party模式的例子,两者非常相似,注意区分本质的意图)。因此外观模式帮助我们屏蔽掉了底层那些繁杂的操作,不过他并没有屏蔽掉你对底层的直接操作,比如洗完澡就可以自动清洗浴缸了,你就可以直接按下浴缸的清洗按钮就可以了,不用等到电影看完后再一起进行。

Coding

明白外观模式的意图和原理,代码实现就非常容易了,首先是我们的智能家居类:

代码语言:javascript复制
// 音箱
public class Amplifier {

    public void on() {
        System.out.println("TV is starting....");
    }

    public void off() {
        System.out.println("TV has stopped!");
    }

    public void setCd() {
        System.out.println("CD has set!");
    }

}

// 灯光
public class RoomLamp {

    public void on() {
        System.out.println("Light on!");
    }

    public void off() {
        System.out.println("Light off!");
    }

}

// 浴缸
public class Bathtub {

    public void on() {
        System.out.println("Bathtub is working!");
    }

    public void off() {
        System.out.println("Bathtub is stopped!");
    }

}

// 电视
public class TV {

    public void on() {
        System.out.println("TV is starting....");
    }

    public void off() {
        System.out.println("TV has stopped!");
    }

}

接着是我们的外观类:

代码语言:javascript复制
public class HomePartyFacade {

    private TV tv;
    private Bathtub bathtub;
    private RoomLamp roomLamp;
    private Amplifier amplifier;

    public HomePartyFacade(TV tv, Bathtub bathtub, RoomLamp roomLamp, Amplifier amplifier) {
        this.tv = tv;
        this.bathtub = bathtub;
        this.roomLamp = roomLamp;
        this.amplifier = amplifier;
    }

    public void startParty() {
        roomLamp.on();
        bathtub.on();
        amplifier.on();
        amplifier.setCd();
        tv.on();
    }

    public void endParty() {
        roomLamp.off();
        amplifier.off();
        tv.off();
    }

}

最后你只需要调用startParty方法就可以开始看电影了,外观模式就是这么简单。不过还没完,外观模式隐含了一个设计原则——最少知道原则(迪米特法则),那什么是最少知道原则呢?

最少知道原则

简单的说,一个类越少被其它类知道越好。为什么呢?我相信大家从开始接触编程起,就听到过高内聚,低耦合的概念,避免在代码修改时牵一发而动全身,最少知道原则就是为了降低各个类之间的耦合而努力。那要如何才能满足这个原则呢?

它提供了一些方针,就任何对象而言,在该对象的方法内,我们只调用属于以下范围的方法:

  • 该对象的本身;
  • 通过方法参数传进的对象;
  • 当前方法实例化的所有对象;
  • 该对象的所有成员变量引用的对象。

简单的说,也就是不要调用另外一次调用所返回的对象的方法(即避免链式调用)。上面的例子里没有链式调用,但是对于用户来说他只想轻松的看场电影,而不想费时费力的去操作一个个开关,所以只需要为他提供一个统一的操作接口,那就只需要记住这个操作的使用就行了,也不用担心以后升级了某些系统而又得去学一遍该如何操作新系统,厂家只需要提供一个新的外观就行了,极大的降低了用户和子系统的耦合度。

不过,我们也不难看出,最少知道原则的缺陷就在于会产生许多的外观中间类,也就使得系统变得更庞大和复杂。因此也不要盲目的遵循这一原则。

总结

外观模式和装饰者模式以及适配器模式都是通过组合来实现各自的目的,在需要简化并统一一群复杂的接口时,使用外观;需要改变接口以符合客户的预期要求时使用适配器模式;而需要给对象增加新的行为和责任时使用装饰者模式。

0 人点赞