设计模式之门面模式

醉酒当歌 提交于 2020-01-01 02:13:23

前言

《三国演义》中有曰:刘备、诸葛亮趁曹操赤壁之战失利,大肆扩充地盘,先后占领荆州大部地区,引起东吴孙权的警惕。为了限制刘备势力的发展,鲁肃奉命向刘备讨还荆州,但遭到拒绝。东吴大都督周瑜向孙权献计:趁刘备的甘夫人病故,用孙权的妹妹孙仁为诱饵,将刘备“赚到南徐,妻子不能勾得,幽囚在狱中”。 但是,这个诡计被诸葛亮一眼识破。他将计就计,让刘备“择日便去就亲”,并派赵云前去保护,并给了赵云三个锦囊,教赵云“依次而行”。结果,使东吴“赔了夫人又折兵”。此为诸葛亮的锦囊三妙计。

三妙计

  • 妙计一:见乔国老,并把刘备娶亲的事情搞得东吴人尽皆知。
  • 妙计二:用谎言(曹操打荆州)骗泡在温柔乡里的刘备回去。
  • 妙计三:让孙夫人摆平东吴的追兵,她是孙权妹妹,东吴将领惧她三分。

妙计的两种实施方案

  • 把三个锦囊直接交给刘备,让刘备根据情况打开锦囊。
  • 把锦囊交给赵云,赵云按照诸葛亮的嘱咐,依次按照情况使用锦囊。

刘备用妙计

妙计的接口
public interface Strategy {
    //妙计内容
    public void carryOut();
}
妙计一
public class StrategyOne implements Strategy {

    @Override
    public void carryOut() {
        System.out.println("见乔国老,并把刘备娶亲的事情搞得东吴人尽皆知。");
    }
}
妙计二
public class StrategyTwo implements Strategy {

    @Override
    public void carryOut() {
        System.out.println("用谎言(曹操打荆州)骗泡在温柔乡里的刘备回去。");
    }
}
妙计三
public class StrategyThree implements Strategy {

    @Override
    public void carryOut() {
        System.out.println("让孙夫人摆平东吴的追兵。");
    }
}
刘备使用妙计
public class Client {
    public static void main(String[] args) {
        //刘备一行人到达南徐的时候,打开第一个锦囊
        Strategy strategyOne=new StrategyOne();
        strategyOne.carryOut();
        //周瑜和孙权通过计谋使刘备沉迷在温柔乡无法自拔
        Strategy strategyTwo=new StrategyTwo();
        strategyTwo.carryOut();
        //周瑜看计谋不行,出兵拦杀刘备
        Strategy strategyThree=new StrategyThree();
        strategyThree.carryOut();
    }
}
输出的结果为:
//刘备一行人到达南徐的时候,打开第一个锦囊
见乔国老,并把刘备娶亲的事情搞得东吴人尽皆知。

//周瑜和孙权通过计谋使刘备沉迷在温柔乡无法自拔
用谎言(曹操打荆州)骗泡在温柔乡里的刘备回去。

//周瑜看计谋不行,出兵拦杀刘备
让孙夫人摆平东吴的追兵。
忽略其他正常因素(诸葛亮不可能把锦囊交给刘备实施),代码角度分析这种方案带来的问题
  • 锦囊使用是有前提的,要根据每个阶段来使用对应的锦囊,在编写代码中要清楚它们的顺序,一旦出错就会造成刘备死翘翘。这在面向对象的编程中是极度地不适合,它根本就没有完成一个类所具有的单一职责。
  • 外界访问直接深入到子系统内部,相互之间是一种强耦合关系,这样的强依赖是系统设计所不能接受的。
  • 子系统的内部方法直接暴露给外部调用,安全性低。
  • 当锦囊数越来越多的时候,那么Client就需要调用更多锦囊类来实现,这就会增加Client的实现难度,维护更加困难。

赵云协助用妙计(门面模式)

诸葛亮能够想到应对之策,当然也会考虑到让谁和如何实施这三个锦囊才能够让刘备顺利化险为夷。综合上面刘备亲自实施锦囊妙计带来的问题,安排赵云保管锦囊并在适当的时机协助实施才是上上之策。

UML实现

在这里插入图片描述
增加了一个ZhaoYunFacadee类,负责对锦囊实施过程进行封装,然后高层模块只要和它有交互就成。

增加的代码模块

赵云充当门面
public class ZhaoYunFacade {
    //妙计一
    private Strategy strategyOne=new StrategyOne();
    //妙计二
    private Strategy strategyTwo=new StrategyTwo();
    //妙计三
    private Strategy strategyThree=new StrategyThree();
   //三妙计统一让赵云协助实施
    public void carryOut(){
        //刘备一行人到达南徐的时候,打开第一个锦囊
        strategyOne.carryOut();
        //周瑜和孙权通过计谋使刘备沉迷在温柔乡无法自拔
        strategyTwo.carryOut();
        //周瑜看计谋不行,出兵拦杀刘备
        strategyThree.carryOut();
    }
}

刘备在遇到困难的时候,只要让赵云根据诸葛亮的锦囊进行处理,这多简单,Client减少了很多工作。

Client
public class Client {
    public static void main(String[] args) {
        //刘备遇到困难,只要通过赵云按照锦囊实施,就可化险为夷
        ZhaoYunFacade zhaoYunFacade=new ZhaoYunFacade();
    zhaoYunFacade.carryOut();;
    }   
}
输出的结果为:
//刘备一行人到达南徐的时候,打开第一个锦囊
见乔国老,并把刘备娶亲的事情搞得东吴人尽皆知。

//周瑜和孙权通过计谋使刘备沉迷在温柔乡无法自拔
用谎言(曹操打荆州)骗泡在温柔乡里的刘备回去。

//周瑜看计谋不行,出兵拦杀刘备
让孙夫人摆平东吴的追兵。

运行结果是相同的。场景类简化了很多,只要与ZhaoYunFacade交互就成了,其他的什么都不用管,什么时候使用锦囊、怎么用都不用管,只要调用ZhaoYunFacade提供的方法,就可以得到想要的妙计,这种方式不仅简单,而且扩展性还非常好,同时不改变子系统对外暴露的接口、方法,只改变内部的处理逻辑,其他兄弟模块的调用产生了不同的结果。

两种方案的程序结构图

  • 没有采用门面模式

在这里插入图片描述

  • 采用门面模式
    在这里插入图片描述
    总的来说,门面对象是外界访问子系统内部的唯一通道,不管子系统内部是多么杂乱无章。

门面模式的介绍

门面模式的定义

门面模式(Facade Pattern)也叫做外观模式。要求一个子系统的外部与其内部的通信必须通过一个统一的对象进行。门面模式提供一个高层次的接口,使得子系统更易于使用。

中介模式的角色介绍

在这里插入图片描述

  • Facade门面角色

客户端可以调用这个角色的方法。此角色知晓子系统的所有功能和责任。一般情况下,本角色会将所有从客户端发来的请求委派到相应的子系统去,也就说该角色没有实际的业务逻辑,只是一个委托类。

  • subsystem子系统角色

可以同时有一个或者多个子系统。每一个子系统都不是一个单独的类,而是一个类的集合。子系统并不知道门面的存在。对于子系统而言,门面仅仅是另外一个客户端而已。

门面模式的使用场景

  • 为一个复杂的模块或子系统提供一个供外界访问的接口。
  • 为降低个人代码质量对整体项目的影响风险,只能在指定的子系统中开发,然后再提供门面接口进行访问操作。
  • 子系统相对独立——外界对子系统的访问只要黑箱操作即可。

门面模式优缺点

优点

减少系统的相互依赖。上面也提到不使用门面模式,外界访问直接深入到子系统内部,相互之间是一种强耦合关系这样的强依赖是系统设计所不能接受的,门面模式的出现就很好地解决了该问题,所有的依赖都是对门面对象的依赖,与子系统无关。
提高了灵活性。依赖减少了,灵活性自然提高了。不管子系统内部如何变化,只要不影响到门面对象,就没有什么问题了。
提高安全性。访问子系统的哪些业务就开通哪些逻辑,不需要把子系统的内部方法直接暴露给外部调用。

缺点

门面模式最大的缺点就是不符合开闭原则,对修改关闭,对扩展开放。系统投产后发现问题唯一能做的一件事就是修改门面角色的代码,这个风险相当大。

简单对比门面模式和中介模式的区别

  • 从定义上,门面模式为复杂的子系统提供一个统一的访问界面,它定义的是一个高层接口,该接口使得子系统更加容易使用,避免外部模块深入到子系统内部而产生与子系统内部细节耦合的问题。中介者模式使用一个中介对象来封装一系列同事对象的交互行为,它使各对象之间不再显式地引用,从而使其耦合松散,建立一个可扩展的应用架构。
  • 从功能上,门面模式只是增加了一个门面,它对子系统来说没有增加任何的功能,子系统若脱离门面模式是完全可以独立运行的。而中介者模式则增加了业务功能,它把各个同事类中的原有耦合关系移植到了中介者,同事类不可能脱离中介者而独立存在。
  • 从关系上,对门面模式来说,子系统不知道有门面存在,而对中介者来说,每个同事类都知道中介者存在,因为要依靠中介者调和同事之间的关系,它们对中介者非常了解。
  • 从封装程度上,门面模式是一种简单的封装,所有的请求处理都委托给子系统完成,而中介者模式则需要有一个中心,由中心协调同事类完成,并且中心本身也完成部分业务,它属于更进一步的业务功能封装。

总结

门面模式是一个很好的封装方法,一个子系统比较复杂时,比如算法或者业务比较复杂,就可以封装出一个或多个门面出来,项目的结构简单,而且扩展性非常好。还有,对于一个较大项目,为了避免人员带来的风险,也可以使用门面模式。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!