设计模式(十):外观模式

大家好,欢迎来到编程队伍,我是作者王小伍,你可以叫我伍先生

这篇文章是设计模式系列文章的第十篇:外观模式

设计模式系列前几篇没看的可以点击对应的文章快速查看

设计模式(一):单例模式

设计模式(二):工厂模式

设计模式(三):生成器模式

设计模式(四):原型模式

设计模式(五):适配器模式

设计模式(六):装饰器模式

设计模式(七):桥接模式

设计模式(八):代理模式

设计模式(九):组合模式


正文

我们还是老规矩,用一个具体案例开始我们的设计模式之旅

假如我们有一个中台系统,系统中有5个接口供业务系统调用

业务系统A需要调用中台系统的前三个接口完成自己的业务逻辑

业务系统B需要调用中台系统的后两个接口来完成业务系统B自己的逻辑

接着是业务系统C、D、E、F等等,他们都和业务系统A或B的需求一样:希望调用中台系统的前三个接口或后两个接口去实现自己系统的业务逻辑

我们会发现,这些业务系统在调用中台系统时存在几个问题

  • 业务系统需要足够了解中台系统的每个接口逻辑,才能决定自己到底该调用哪些接口

  • 业务系统在调用中台系统接口时,需要调用多个接口,非常麻烦

  • 多个业务系统存在相同的代码,导致整体工作量增加

我们可以这样对中台系统进行改造,让业务系统调用更简单

在中台系统中增加接口A ,在接口A里面分别分别调用接口1、2、3。业务系统A可以直接调用接口A来完成自己的业务

同样的,中台系统中增加接口B,在接口B中分别调用接口4、5。业务系统B可以直接调用接口B来完成自己的业务

这样我们就解决了刚才所说的3个问题

  • 业务系统不需要了解中台系统具体的接口逻辑,只需要调用对应的接口即可

  • 业务系统调用中台系统时不再是多个接口,只需要调用一个接口

  • 原来的多个业务系统中相同的代码被封装在了接口A或接口B中,业务系统相应的工作量会减少

这种实现方式就是在中台系统中使用了外观模式,接口A和接口B就是中台系统的门面(外观模式也叫门面模式)

下面我们用java代码来模拟一下中台系统外观模式的实现方式

首先是中台系统的5个接口,这里用5个方法代表接口

public class Center {
    public void method1(){} // 模拟接口1
    public void method2(){} // 模拟接口2
    public void method3(){} // 模拟接口3
    public void method4(){} // 模拟接口4
    public void method5(){} // 模拟接口5
}

接下来是中台系统中的外观类,里面包含了接口A和接口B。同样用两个方法来代表接口

在接口A中调用了中台系统的前3个方法;在接口B中调用了中台系统中的后两个方法

public class CenterFacade {
    private Center center = new Center();

    // 模拟接口A
    public void centerA() {
        center.method1();
        center.method2();
        center.method3();
    }

    // 模拟接口B
    public void centerB() {
        center.method4();
        center.method5();
    }
}

业务系统A在调用时,使用外观类中的接口A即可实现自己的业务逻辑

CenterFacade centerFacade = new CenterFacade();
centerFacade.centerA();

业务系统B在调用时,使用外观类中的接口B即可实现自己的业务逻辑

CenterFacade centerFacade = new CenterFacade();
centerFacade.centerB();

基本介绍

外观模式也叫门面模式,在创建型模式、结构型模式和行为型模式分类中,外观模式归属于结构型模式

在我们实际的工作中,外观模式是最常用的一种设计模式之一

比如,我们把几个方法中共用的逻辑抽象成一个独立的方法,那么这个方法就可以理解成外观模式

外观模式是通过引入一个外观角色来简化调用者与各个子系统之间的交互,为复杂的子系统调用提供一个统一的入口,降低子系统与调用者的耦合度,使得扩展更加方便

外观模式实现步骤:

  1. 抽象各个子系统的业务逻辑

  2. 将抽象过的业务逻辑封装到门面类中

  3. 调用者使用门面类中的方法完成自己的逻辑

优点

外观模式给各个子系统提供统一的入口,调用者使用起来很简单

外观模式把各个子系统和调用者解耦,扩展性会更好。比如,想要增加一个子系统时,只需要按照外观模式的规范进行开发,调用者和外观类都不用修改

缺点

如果设计不合理,增加新的子系统时可能需要修改外观类或调用者的源代码,违背了“开闭原则”

适用场景

1、需要为一个复杂的子系统提供一系列逻辑支持的时候,可以考虑使用外观模式

比如,上文中提到的案例。中台系统需要给业务系统提供多个方法支持,可以用外观模式

2、当调用者需要调用多个子系统来完成自己的逻辑时,可以考虑使用外观模式

比如日志处理框架 SLF4J,它对调用者提供接口。logbacklog4j等各种日志框架作为子系统去实现这些接口

业务系统需要记录日志时,调用SLF4J门面类即可,而不必关心具体使用的是哪一个框架

与其他模式关系

  • 与单例模式的关系

外观类通常都是单例类,因为大部分情况下一个外观实例就足够了

单例模式回顾:设计模式(一):单例模式

  • 与适配器模式的关系

适配器模式通常只封装一个对象,外观模式会封装多个对象

外观模式把子系统逻辑进行封装,对外提供一个新接口;适配器模式则试图使用已有接口

适配器模式回顾:设计模式(五):适配器模式

  • 与代理模式的关系

外观模式与代理模式的相似之处在于它们都缓存了一个复杂对象,并负责管理这个对象的生命周期

不同的是,代理模式中代理对象是原对象的子类对象,它们对外提供统一的接口

外观模式中的外观类与原对象不存在父子关系,外观类是把各个子系统的接口进行封装后再对外提供

代理模式回顾:设计模式(八):代理模式

  • 与抽象工厂模式的关系

通常情况下我们会使用外观模式加抽象工厂对外提供统一接口

但是,当外观模式中没有复杂逻辑,只有对象创建的过程时,可以使用抽象工厂模式来代替外观模式

工厂模式回顾:设计模式(二):工厂模式

最后还是那句话,设计模式不是万能的,只有合理利用设计模式才能写出合理的代码

-- 以上内容来自公众号 编程队伍,转载请注明出处


版权声明:本文为as576228266原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。