博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
门面模式就是这么简单
阅读量:6786 次
发布时间:2019-06-26

本文共 3935 字,大约阅读时间需要 13 分钟。

上篇文章我们学习了适配器模式,我们知道它是将一个接口转换成另一个符合用户期望的接口,它的主要目的是为了兼容,将一个不兼容接口的对象包装起来,变成兼容的对象。

这篇文章我们来学习一下门面模式,它又称为外观模式,与适配器模式看起来很类似,但它主要是为了简化接口,下面就来具体看一下。

门面模式

不知道大家平时是否有这样的经历。每天开启电脑后,要打开各种软件、IDE、工具,就需要一个一个地点击桌面图标;到了晚上又要一个个地关闭,感觉非常麻烦。

这里举几个例子,首先是 Intellj IDEA:

public class IDEA {    public void on() {        System.out.println("打开 IDEA");    }    public void off() {        System.out.println("关闭 IDEA");    }}复制代码

然后是 Google:

public class Google {    private List
tabs = new ArrayList<>(); public void on() { System.out.println("打开 google"); } public void off() { System.out.println("关闭 google"); } public void onTabs() { System.out.println("打开 ProcessOn、七牛云等 Tab"); }}复制代码

还有有道云笔记:

public class YouDaoNote {    public void on() {        System.out.println("打开 YouDaoNote");    }    public void off() {        System.out.println("关闭 YouDaoNote");    }}复制代码

可能还会有 Weixin:

public class WeiXin {    public void on() {        System.out.println("打开 WeiXin");    }    public void off() {        System.out.println("关闭 WeiXin");    }}复制代码

另外,可能还会有 Shell、CloudMusic 等。我们开启软件时,可以如下写:

public class Client {    public static void main(String[] args) {        IDEA idea = new IDEA();        Google google = new Google();        YouDaoNote youDaoNote = new YouDaoNote();        WeiXin weiXin = new WeiXin();        idea.on();        google.on();        google.onTabs();        youDaoNote.on();        weiXin.on();    }}复制代码

在关闭时,又将这些步骤反过来执行一遍,那也太麻烦了。其实,我们可以写一个 bat 脚本,每次只需要执行这个脚本,就可以开启多个软件。

这个脚本就是所谓的门面,现在我们来创建一个门面,它将不同的软件组合成一个统一的接口:

public class DevelopmentEnvironment {    private IDEA idea;    private Google google;    private YouDaoNote youDaoNote;    private WeiXin weiXin;    public DevelopmentEnvironment(IDEA idea, Google google, YouDaoNote youDaoNote, WeiXin weiXin) {        this.idea = idea;        this.google = google;        this.youDaoNote = youDaoNote;        this.weiXin = weiXin;    }    public void buildEnvironment() {        idea.on();        google.on();        google.onTabs();        youDaoNote.on();        weiXin.on();    }    public void shutEnvironment() {        idea.off();        google.off();        youDaoNote.off();        weiXin.off();    }}复制代码

它对外只暴露了几个方法,于是我们建立开发环境可以这样写:

public class Client {    public static void main(String[] args) {        IDEA idea = new IDEA();        Google google = new Google();        YouDaoNote youDaoNote = new YouDaoNote();        WeiXin weiXin = new WeiXin();        DevelopmentEnvironment environment = new DevelopmentEnvironment(idea, google, youDaoNote, weiXin);        environment.buildEnvironment();    }}复制代码

上述模式就是门面模式,它提供了一个统一的接口,来访问子系统的多个接口,使得子系统更容易使用。

它的 UML 图如下:

下面来总结一下门面模式的优点:

  • 通过统一的接口,来访问子系统的多个接口。如此就无需了解子系统的实现,简化了调用的过程。
  • 减少了客户和子系统之间的系统依赖,耦合度更低。
  • 门面模式很好得符合了最少知道原则。

缺点:

  • 如果增加子系统,或者扩展子系统的行为,可能会引入风险;
  • 系统设计不当时,增加子系统可能需要修改门面类,这违背了开闭原则。

最少知道原则

其实门面模式很好地符合了最少知道原则,它指的是尽量减少对象之间的交互。在设计中,我们应该减少类之间的耦合度,以免修改系统中一部分,而影响到其他部分。

为满足该原则,我们应该只调用属于以下范围的方法:

  1. 该对象本身;
  2. 被当作方法的参数而传递进来的对象;
  3. 此方法所创建或实例化的任何对象;
  4. 对象的任何组件;

例如下面的例子就符合最少知识原则:

public class Car {    Engine engine; // 对象的组件        public Car() {}        // key 为作为方法参数传递进来的对象    public void start(Key key) {        Door door = new Door(); // 该方法中创建的对象                boolean authorized = key.turn(); // 调用作为方法参数传递进来的对象的方法,2        if(authorized) {            engine.start(); // 调用组件的方法 // 4            updateDashboardDisplay(); // 调用对象本身的方法 // 1            door.lock(); // 调用该方法中创建的对象的方法 // 2        }    }        // 对象本身的方法    public void updateDasnboardDisplay() {}}复制代码

门面模式的具体实践

在实际项目中,我们都会记录应用的执行日志,常用的日志框架有许多,而不同的中间件会集成不同的日志框架,当集成这些中间件时,我们的系统不得不维护去多种日志框架。

于是,我们可以引入一个中间层,由这个中间层来决定使用哪一个具体的日志实现。这个中间层就是日志门面,我们在打印日志时,只需要调用日志门面的 API,而不需要关心日志具体的实现。

日志门面和日志实现主要有:

  • 日志门面(日志的抽象层):slf4j、jcl(commons-logging);
  • 日志实现:jul(java.util.logging)、logback、log4j、log4j2;

具体它们的原理,这里就不说了。

在实际使用时,例如 SpringBoot 中默认使用 Slfj + Logback 组合来打印日志。

参考资料

  • 《Head First 设计模式》

转载于:https://juejin.im/post/5cdb7c09e51d453ae21957f7

你可能感兴趣的文章
维珍银河完成最长距离火箭飞行,下一步剑指太空旅行
查看>>
[Python]attributeError:'module' object has no attribute 'dump'
查看>>
Docker系列教程11-使用Nexus管理Docker镜像
查看>>
业界最全,阿里云混合云灾备服务上线!
查看>>
Windows Linux 子系统可以在资源管理器中打开
查看>>
WebStorm文件类型关联设置
查看>>
13.1 Spring MVC 关于controller的字符编码
查看>>
理发店与 App 定价模型
查看>>
ES6(数组)
查看>>
php simplexml_load_file 函数执行不稳定
查看>>
C#,VB.NET如何将Word转换为PDF和Text
查看>>
玩转Kafka的生产者
查看>>
解决android.permission.WRITE_APN_SETTINGS
查看>>
py编程技巧-1.1-如何在列表、字典、集合中根据条件筛选数据
查看>>
Ruby on Rails: UUID as your ActiveRecord primary key
查看>>
Bean property属性说明
查看>>
微软工程师认为 Mozilla 也应该拥抱 Chromium
查看>>
去年出货的工业机器人,超过1/3都跑来了中国
查看>>
Windows死机的话,可能的一些猫病
查看>>
作为架构师,你必需要搞清楚的概念:POJO、PO、DTO、DAO、BO、VO
查看>>