Facade Pattern 外观模式

在这里插入图片描述

模式思想

在介绍该模式之前,我们先来看一个生活中的案例。当你下班回家后,需要把家里的电器一个一个依次打开,开电视、开空调、开灯……,而当你准备出门上班时,又要把之前打开的电器一个一个依次关掉,关电视、关空调、关灯……。这样家里电器一多以后,每次开开关关是很麻烦的。那么我们就会想如果有一个万能开关,可以直接一次性控制家中全部电器的开关。这样是不是就方便很多了?每次回家或者上班出门,只需按一下万能开关就可以完成之前的多次开关操作了

利用我们在现实世界获得的指引,将其运用于软件工程领域下,即提炼为我们今天所要介绍的设计模式——Facade Pattern外观模式,其又被称作为门面模式。在这个例子中,家中的各个电器可以称之为子系统,而这个万能开关就是外观模式中的外观角色。很多时候client不应该需要了解各个子系统的工作流程,否则会造成client与各子系统之间的高度耦合。那么我们就可以通过一个外观角色,其负责将子系统及工作流程进行封装以简化client的使用。在Facade Pattern外观模式中,涉及以下两个角色

  • 子系统角色:通常来说在一个系统中会有若干个子系统(比如本文例子中的各个家用电器)。client即可以直接调用各个子系统,也可以通过外观角色来实现对各子系统的调用
  • 外观角色:其通过将各子系统的方法调用逻辑、顺序的有机组合、封装。大大简化了client使用各子系统的流程及难度,降低了client与各子系统之间的耦合度

实践

现在我们通过Java实现上文提到的生活例子。首先定义实现家里各个子系统——各电器类

/**
 * 子系统:电视
 */
public class Tv {
    /**
     * 打开电视
     */
    public void turnOn() {
        System.out.println("打开电视 ... ");
    }

    /**
     * 关闭电视
     */
    public void turnOff() {
        System.out.println("关闭电视");
    }
}
...
/**
 * 子系统:加湿器
 */
public class Humidifier {
    /**
     * 打开加湿器
     */
    public void turnOn() {
        System.out.println("打开加湿器 ... ");
    }

    /**
     * 关闭加湿器
     */
    public void turnOff() {
        System.out.println("关闭加湿器");
    }
}
...
/**
 * 子系统:空调
 */
public class AirConditioner {
    /**
     * 打开空调
     */
    public void turnOn() {
        System.out.println("打开空调 ... ");
    }

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

由于现在我们还没引入外观模式,隔壁老王每次回到家、出门时都只好亲自操作各个家电,如下所示

/**
 * 外观模式Demo
 */
public class FacadePatternDemo {
    public static void main(String[] args) {
        System.out.println("---------------- Test 1 ----------------");
        // 不使用外观模式,客户端(老王)直接访问各子系统(各电器)
        Tv tv = new Tv();
        AirConditioner airConditioner = new AirConditioner();
        Humidifier humidifier = new Humidifier();

        System.out.println("【老王下班回到家,打开家中所有电器】");
        tv.turnOn();
        airConditioner.turnOn();
        humidifier.turnOn();

        System.out.println("【老王准备出门上班,关闭家中所有电器】");
        tv.turnOff();
        airConditioner.turnOff();
        humidifier.turnOff(); 
    }
}

从下面的结果可以看到虽然操作有点麻烦,但结果至少符合预期

测试结果
在这里插入图片描述

既然这里我们介绍了外观模式,就利用该模式来优化下吧。一般来说子系统一般已经先行存在了,那么实际上我们就只需要再引入一个外观角色——即家用电器的外观角色ElectricApplianceFacade类。可以看到,其内部持有了各个子系统对象,并将多个子系统的操作有机地进行组合、封装。据此实现client使用的方便简洁

/**
 * 家用电器的外观角色
 */
public class ElectricApplianceFacade {
    /**
     * 子系统:电视
     */
    private Tv tv;

    /**
     * 子系统:空调
     */
    private AirConditioner airConditioner;

    /**
     * 子系统:加湿器
     */
    private Humidifier humidifier;

    public ElectricApplianceFacade() {
        this.tv = new Tv();
        this.airConditioner = new AirConditioner();
        this.humidifier = new Humidifier();
    }

    /**
     * 打开所有家用电器
     */
    public void turnOnAll() {
        tv.turnOn();
        airConditioner.turnOn();
        humidifier.turnOn();
    }

    /**
     * 关闭所有家用电器
     */
    public void turnOffAll() {
        tv.turnOff();
        airConditioner.turnOff();
        humidifier.turnOff();
    }
}

好了,现在引入了外观模式,隔壁老哥再也不用一个一个的开、关家电了,而是通过外观角色就可以很方便地实现一键开关

/**
 * 外观模式Demo
 */
public class FacadePatternDemo {
    public static void main(String[] args) {
        System.out.println("---------------- Test 2 ----------------");
        // 使用外观模式,客户端(老王)通过外观角色间接访问各子系统(各电器)
        ElectricApplianceFacade electricApplianceFacade = new ElectricApplianceFacade();

        System.out.println("【老王下班回到家,打开家中所有电器】");
        electricApplianceFacade.turnOnAll();

        System.out.println("【老王准备出门上班,关闭家中所有电器】");
        electricApplianceFacade.turnOffAll();
    }
}
测试结果
在这里插入图片描述

迪米特法则

迪米特法则,又称作最少知识原则。其内涵是一个对象对其它对象的了解程度应该尽可能的小,以降低彼此之间的耦合。显然我们可以看到,Facade Pattern外观模式就是迪米特法则的具体实践

应用

外观模式在第三方框架、组件中亦被大量使用。这里只提下其在Java日志框架下的应用。众所周知,Java下的日志框架非常繁多,有JDK Logging、Log4J、Log4J2、LogBack等,一旦变更项目中现有的日志框架选型,就需要进行大量相应的修改非常麻烦。为此SLF4J应运而生,其与其它日志框架不同的地方在于,其不是一个具体的日志框架,而是一个简单的日志框架的外观。在实际项目中,一般我们是通过SLF4J这个日志外观角色来使用日志,而不是直接显式操作、使用某一个具体的日志框架,以降低耦合度,也便于后期升级、变更具体日志框架的选型

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值