外观模式(Facade Pattern)

1. 介绍

1.1 定义&图解

定义了一个高层、统一的接口,外部通过这个统一的接口对子系统中的一群接口进行访问。

通过创建一个统一的外观类,用来包装子系统中一个或多个复杂的类,客户端可以通过调用这个外观类的方法来调用内部子系统中所有方法。

图解:


外观模式图解1.png

网站的导航例子:以前我需要在搜索栏逐个搜索网站地址,有了网站导航(外观模式)后,就方便很多了,如下图。


外观模式图解2.png

1.2 主要作用

  • 实现客户类与子系统类的松耦合。
  • 降低原有系统的复杂度。
  • 提高了客户端使用的便捷性,使得客户端无须关心子系统的工作细节,通过外观角色即可调用相关功能。
  1. 引入外观角色之后,用户只需要与外观角色交互;
  2. 用户与子系统之间的复杂逻辑关系由外观角色来实现。

1.3 解决的问题

  • 避免了客户端系统与子系统之间的高耦合度
  • 使得复杂的子系统用法变得简单

2. 模式原理

2.1 UML类图 & 组成

外观模式UML.png

2.2 实例讲解

接下来我用一个实例来对建造者模式进行更深一步的介绍。

a. 实例概况

  • 背景:小成的爷爷已经80岁了,一个人在家生活,每次起床后都需要打开灯、打开电视、打开空调;睡觉前都需要关闭灯、关闭电视、关闭空调。
  • 冲突:行动不方便,走过去关闭那么多电器很麻烦。
  • 解决方案:小成买了一个智能家具控制器(外观对象/统一接口)给他爷爷,他爷爷只需要一键就能打开/关闭 灯、电视机、空调。
  1. 即用外观模式来为所有子系统设计一个统一的接口
  2. 客户端只需要调用外观类中的方法就可以了,简化了客户端的操作

b. 代码如下

电器类

//灯类
public class SubSystemA_Light {
    public void on(){
        System.out.println("打开了灯...");
    }
    public void off(){
        System.out.println("关闭了灯...");
    }
}

//电视类
public class SubSystemB_Television {
    public void on(){
        System.out.println("打开了电视...");
    }
    public void off(){
        System.out.println("关闭了电视...");
    }
}

//空调类
public class SubSystemC_Aircondition {
    public void on(){
        System.out.println("打开了空调...");
    }
    public void off(){
        System.out.println("关闭了空调...");
    }
}

外观类:智能遥控器

public class Facade {
    private SubSystemA_Light light;
    private SubSystemB_Television television;
    private SubSystemC_Aircondition aircondition;
    //构造方法传参
    public Facade(SubSystemA_Light light,SubSystemB_Television television,SubSystemC_Aircondition aircondition){
        this.light = light;
        this.television  = television ;
        this.aircondition =aircondition;
    }
    //起床后一键开电器
    public void on(){
        System.out.println("起床了");
        light.on();
        television.on();
        aircondition.on();
    }
    //睡觉时一键关电器
    public void off(){
        System.out.println("睡觉了");
        light.off();
        television.off();
        aircondition.off();
    }
}

客户端调用

public class FacadePattern {
    public static void main(String[] args){
        SubSystemA_Light light = new SubSystemA_Light();
        SubSystemB_Television television = new SubSystemB_Television();
        SubSystemC_Aircondition aircondition = new SubSystemC_Aircondition();

        /***********不使用外观模式时的情况***********/
        //起床后开电器
        System.out.println("起床了");
        light.on();
        television.on();
        aircondition.on();
        System.out.println("可以看电视了");
        //睡觉时关电器
        System.out.println("睡觉了");
        light.off();
        television.off();
        aircondition.off();
        System.out.println("可以睡觉了");
        System.out.println("----------------------------------------");

        /***********使用外观模式时的情况***********/
        //外观模式构造方法传参
        Facade facade = new Facade(light,television,aircondition);
        //客户端直接与外观对象进行交互
        facade.on();
        System.out.println("可以看电视了");
        facade.off();
        System.out.println("可以睡觉了");
    }
}

输出结果

起床了
打开了灯...
打开了电视...
打开了空调...
可以看电视了
睡觉了
关闭了灯...
关闭了电视...
关闭了空调...
可以睡觉了
----------------------------------------
起床了
打开了灯...
打开了电视...
打开了空调...
可以看电视了
睡觉了
关闭了灯...
关闭了电视...
关闭了空调...
可以睡觉了

c. 解释说明

  1. 从上面客户端调用的情况可以看出,在不使用外观模式的情况下,小成爷爷需要对每个电器都进行操作,非常不方便。
  2. 客户端与三个子系统都发送了耦合,使得客户端程序依赖与子系统。

3. 优缺点

3.1 优点

  • 降低了客户类与子系统类的耦合度,实现了子系统与客户之间的松耦合关系。
  1. 只是提供了一个访问子系统的统一入口,并不影响用户直接使用子系统类。
  2. 减少了与子系统的关联对象,实现了子系统与客户之间的松耦合关系,松耦合使得子系统的组件变化不会影响到它的客户。
  • 外观模式对客户屏蔽了子系统组件,从而简化了接口,减少了客户处理的对象数目并使子系统的使用更加简单。
  1. 引入外观角色之后,用户只需要与外观角色交互;
  2. 用户与子系统之间的复杂逻辑关系由外观角色来实现。
  • 降低原有系统的复杂度和系统中的编译依赖性,并简化了系统在不同平台之间的移植过程。

因为编译一个子系统一般不需要编译所有其他的子系统。一个子系统的修改对其他子系统没有任何影响,而且子系统内部变化也不会影响到外观对象。

3.2 缺点

  • 在不引入抽象外观类的情况下,增加新的子系统可能需要修改外观类或客户端的源代码,违背了“开闭原则”。
  • 不能很好地限制客户使用子系统类,如果对客户访问子系统类做太多的限制则减少了可变性和灵活性。

4. 应用场景

  • 要为一个复杂的子系统对外提供一个简单的接口。
  • 提供子系统的独立性。
  • 客户程序与多个子系统之间存在很大的依赖性。

引入外观类将子系统与客户以及其他子系统解耦,可以提高子系统的独立性和可移植性。

  • 在层次化结构中,可以使用外观模式定义系统中每一层的入口。

层与层之间不直接产生联系,而通过外观类建立联系,降低层之间的耦合度。

4. 感谢

外观模式(Facade Pattern) - 最易懂的设计模式解析

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,033评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,725评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,473评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,846评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,848评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,691评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,053评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,700评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,856评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,676评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,787评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,430评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,034评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,990评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,218评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,174评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,526评论 2 343