案例:有ModuleA,ModuleB,ModuleC三个类,这三个类实现三个不同的方法 1.按照普通思路,客户端如果想要和这三个类打交道,一般的做法就是直接引入三个类,分别进行实例化,然后引用三个类中的方法 2.采用外观模式,客户端无需知道这三个类的存在,只需要和外观层进行交互即可
下面先讲解一下采用普通方法的实现
1.定义接口
为了更加深刻的体会面向协议编程,我这里采用的都是协议方式,上述三者是定义了A,B,C三者的协议(用协议的好处是面向对象,后续增加新的协议方法比较方便集中管理)
2.实现协议
3.客户端调用
我们可以看到,用普通方法进行实现的时候,客户端必须要知道每一个类(即引入所有的头文件),如此一来客户端和各个实现类的关系耦合度就太大了,不利于扩展修改,同时也不满足接口隔离的原则,如果实现类新增或者改变了,客户端也要做相应的改变。 那么如果想要隔离客户端与各个子模块实现类的交互该怎么办呢?
外观模式就很好地解决了这个难题,下面从一张UML图来看外观模式:
客户端从始至终只需要和Facade进行打交道
外观模式实现
接口定制和子模块的具体实现前面已经有了,这里只需要看下外观类和客户端调用即可
外观类实现
我们看到普通方法中的客户端调用的实现到了这里来了
客户端调用
客户端调用更加清爽了
下面详细讲述一下什么是外观模式。 相信看到这里,我们也能大致推测出,外观模式无非就是一层外衣,包裹住里面的子模块,客户端接触的只有这一层外衣,具体里面是什么,实现了什么,完全不用管,子模块和客户端的解耦也是很彻底的.
外观模式不是为了给子模块添加新的功能接口,而是让外部与内部子模块的耦合度降低,它只是用来包装已有的功能,负责组合已有功能来实现客户端的需要,说白了就是我有N多个功能模块,现在我有一个需求需要实现这些模块中的某几个,那就可以用外观来包一下供给外界使用。
前面也可以看到外观模式无非就是把客户端代码搬到了外观类中,由外观类包装,客户端调用,然而本质上是有变化的。外观类所在层面不是客户端,而是系统(组件),它屏蔽了客户端和内部模块的交互,将各个子模块组合成为一个整体,封装了内部具体的实现细节,方便了外界的调用。此外,外观模式的功能还可以被多个客户端调用,如果有N个客户端实现的功能模块一样,直接调用外观类即可,这样就实现了很好地复用,外观模式的本质就是,封装交互,简化调用,体现了最少知识原则
下面说一下外观模式的优缺点:
优点
- 松耦合
- 简单易用
- 更好地划分访问层次
缺点
- 过多的或者不合理的facade容易让人迷惑