今天看啥  ›  专栏  ›  康小庄

设计模式学习11(Java实现)——外观模式

康小庄  · 简书  ·  · 2021-06-26 10:34

写在前面

  • 记录学习设计模式的笔记
  • 提高对设计模式的灵活运用

学习地址

https://www.bilibili.com/video/BV1G4411c7N4

https://www.bilibili.com/video/BV1Np4y1z7BU

参考文章

http://c.biancheng.net/view/1317.html

项目源码
https://gitee.com/zhuang-kang/DesignPattern

13,外观模式

13.1 外观模式的定义和特点

外观(Facade)模式又叫作门面模式, 是一种通过为多个复杂的子系统提供一个一致的接口,而使这些子系统更加容易被访问的模式。 该模式对外有一个统一接口,外部应用程序不用关心内部子系统的具体细节,这样会大大降低应用程序的复杂度,提高了程序的可维护性。

外观(Facade)模式是“迪米特法则”的典型应用, 它有以下主要优点。

  1. 降低了子系统与客户端之间的耦合度,使得子系统的变化不会影响调用它的客户类。
  2. 对客户屏蔽了子系统组件,减少了客户处理的对象数目,并使得子系统使用起来更加容易。
  3. 降低了大型软件系统中的编译依赖性,简化了系统在不同平台之间的移植过程,因为编译一个子系统不会影响其他的子系统,也不会影响外观对象。

外观(Facade)模式的主要缺点如下。

  1. 不能很好地限制客户使用子系统类,很容易带来未知风险。
  2. 增加新的子系统可能需要修改外观类或客户端的源代码,违背了“开闭原则”。

13.2 外观模式的结构与实现

13.2.1 外观模式的结构

外观(Facade)模式包含以下主要角色。

  1. 外观(Facade)角色:为多个子系统对外提供一个共同的接口。
  2. 子系统(Sub System)角色:实现系统的部分功能,客户可以通过外观角色访问它。
  3. 客户(Client)角色:通过一个外观角色访问各个子系统的功能。

13.2.2 代码实现

关系类图

image

AirCondition

package com.zhuang.facade;

/**
 * @Classname AirCondition
 * @Description 空调类
 * @Date 2021/3/24 19:23
 * @Created by dell
 */

public class AirCondition {
    public void on() {
        System.out.println("空调打开...");
    }

    public void off() {
        System.out.println("空调关闭...");
    }
}

Light

package com.zhuang.facade;

/**
 * @Classname Light
 * @Description 电灯类
 * @Date 2021/3/24 19:23
 * @Created by dell
 */

public class Light {
    public void on() {
        System.out.println("电灯打开...");
    }

    public void off() {
        System.out.println("电灯关闭...");
    }
}

TV

package com.zhuang.facade;

/**
 * @Classname TV
 * @Description 电视类
 * @Date 2021/3/24 19:23
 * @Created by dell
 */

public class TV {
    public void on() {
        System.out.println("电视打开...");
    }

    public void off() {
        System.out.println("电视关闭...");
    }
}

SmartAppliancesFacade

package com.zhuang.facade;

/**
 * @Classname SmartAppliancesFacade
 * @Description 智能音箱类  外观类
 * @Date 2021/3/24 19:24
 * @Created by dell
 */

public class SmartAppliancesFacade {
    private Light light;
    private TV tv;
    private AirCondition airCondition;

    public SmartAppliancesFacade() {
        light = new Light();
        tv = new TV();
        airCondition = new AirCondition();
    }

    //私有打开方法 外界访问不了
    //一键打开
    private void on() {
        light.on();
        tv.on();
        airCondition.on();
    }

    //私有关闭方法 外界访问不了
    //一键关闭
    private void off() {
        light.off();
        tv.off();
        airCondition.off();
    }

    //判断方法
    public void say(String message) {
        if (message.contains("打开")) {
            on();
        } else if (message.contains("关闭")) {
            off();
        } else {
            System.out.println("你说的指令我听不懂!!!");
        }

    }
}

Client

package com.zhuang.facade;

/**
 * @Classname Client
 * @Description 外观模式测试类
 * @Date 2021/3/24 19:24
 * @Created by dell
 */

public class Client {
    public static void main(String[] args) {
        SmartAppliancesFacade smartAppliancesFacade = new SmartAppliancesFacade();
        smartAppliancesFacade.say("打开家电");
        System.out.println("=================");
        smartAppliancesFacade.say("关闭家电");
    }
}
image

13.3 外观模式的应用场景

  • 对分层结构系统构建时,使用外观模式定义子系统中每层的入口点可以简化子系统之间的依赖关系。
  • 当一个复杂系统的子系统很多时,外观模式可以为系统设计一个简单的接口供外界访问。
  • 当客户端与多个子系统之间存在很大的联系时,引入外观模式可将它们分离,从而提高子系统的独立性和可移植性。

13.4 源码解析

使用tomcat作为web容器时,接收浏览器发送过来的请求,tomcat会将请求信息封装成ServletRequest对象,如下图①处对象。但是大家想想ServletRequest是一个接口,它还有一个子接口HttpServletRequest,而我们知道该request对象肯定是一个HttpServletRequest对象的子实现类对象,到底是哪个类的对象呢?可以通过输出request对象,我们就会发现是一个名为RequestFacade的类的对象。

image

RequestFacade类就使用了外观模式

image

为什么在此处使用外观模式呢?

定义 RequestFacade 类,分别实现 ServletRequest ,同时定义私有成员变量 Request ,并且方法的实现调用 Request 的实现。然后,将 RequestFacade上转为 ServletRequest 传给 servlet 的 service 方法,这样即使在 servlet 中被下转为 RequestFacade ,也不能访问私有成员变量对象中的方法。既用了 Request ,又能防止其中方法被不合理的访问。

写在最后

  • 如果我的文章对你有用,请给我点个👍,感谢你😊!
  • 有问题,欢迎在评论区指出!💪



原文地址:访问原文地址
快照地址: 访问文章快照