3.3 模式讲解3.3.1 认识外观模式(1)外观模式的目的 外观模式的目的不是给子系统添加新的功能接口,而是为了让外部减少与子系统内多个模块的交互,松散耦合,从而让外部能够更简单的使用子系统。 这点要特别注意,因为外观是当作子系统对外的接口出现的,虽然也可以在这里定义一些子系统没有的功能,但不建议这么做。外观应该是包装已有的功能,它主要负责组合已有功能来实现客户需要,而不是添加新的实现。 (2)使用外观跟不使用相比有何变化 看到Facade的实现,可能有些朋友会说,这不就是把原来在客户端的代码搬到Facade里面了吗?没有什么大变化啊? 没错,说的很对,表面上看就是把客户端的代码搬到Facade里面了,但实质是发生了变化的,请思考:Facade到底位于何处呢?是位于客户端还是在由A、B、C模块组成的系统这边呢? 答案肯定是在系统这边,这有什么不一样吗? 当然有了,如果Facade在系统这边,那么它就相当于屏蔽了外部客户端和系统内部模块的交互,从而把A、B、C模块组合成为一个整体对外,不但方便了客户端的调用,而且封装了系统内部的细节功能,也就是说Facade与各个模块交互的过程已经是内部实现了。这样一来,如果今后调用模块的算法发生了变化,比如变化成要先调用B,然后调用A,那么只需要修改Facade的实现就可以了。 另外一个好处,Facade的功能可以被很多个客户端调用,也就是说Facade可以实现功能的共享,也就是实现复用。同样的调用代码就只用在Facade里面写一次就好了,而不用在多个调用的地方重复写。 还有一个潜在的好处,对使用Facade的人员来说,Facade大大节省了他们的学习成本,他们只需要了解Facade即可,无需再深入到子系统内部,去了解每个模块的细节,也不用和这多个模块交互,从而使得开发简单,学习也容易。 (3)有外观,但是可以不使用 虽然有了外观,如果有需要,外部还是可以绕开Facade,直接调用某个具体模块的接口,这样就能实现兼顾组合功能和细节功能。比如在客户端就想要使用A模块的功能,那么就不需要使用Facade,可以直接调用A模块的接口。 示例代码如下:
(4)外观提供了缺省的功能实现 现在的系统是越做越大、越来越复杂,对软件的要求也就更高。为了提高系统的可重用性,通常会把一个大的系统分成很多个子系统,再把一个子系统分成很多更小的子系统,一直分下去,分到一个一个小的模块,这样一来,子系统的重用性会得到加强,也更容易对子系统进行定制和使用。 但是这也带来一个问题,如果用户不需要对子系统进行定制,仅仅就是想要使用它们来完成一定的功能,那么使用起来会比较麻烦,需要跟这多个模块交互。 外观对象就可以为用户提供一个简单的、缺省的实现,这个实现对大多数的用户来说都是已经足够了的。但是外观并不限制那些需要更多定制功能的用户,直接越过外观去访问内部的模块的功能。 (5)外观模式的调用顺序示意图 外观模式的调用顺序如图3.6所示: 图3.6 外观模式调用顺序示意图 3.3.2 外观模式的实现(1)Facade的实现 对于一个子系统而言,外观类不需要很多,通常可以实现成为一个单例。 也可以直接把外观中的方法实现成为静态的方法,这样就可以不需要创建外观对象的实例而直接就可以调用,这种实现相当于把外观类当成一个辅助工具类实现。简要的示例代码如下:
(2)Facade可以实现成为interface 虽然Facade通常直接实现成为类,但是也可以把Facade实现成为真正的interface,只是这样会增加系统的复杂程度,因为这样会需要一个Facade的实现,还需要一个来获取Facade接口对象的工厂,此时结构如图3.7所示: 图3.7 外观实现成为接口的结构示意图 (3)Facade实现成为interface的附带好处 如果把Facade实现成为接口,还附带一个功能,就是能够有选择性的暴露接口方法,尽量减少模块对子系统外提供的接口方法。 换句话说,一个模块的接口里面定义的方法可以分成两部分,一部分是给子系统外部使用的,一部分是子系统内部的模块间相互调用时使用的。有了Facade接口,那么用于子系统内部的接口功能就不用暴露给子系统外部了。 比如,定义如下的A、B、C模块的接口:
同理定义B、C模块的接口
定义好了各个模块的接口,接下来定义Facade的接口:
这样定义Facade的话,外部只需要有Facade接口,就不再需要其它的接口了,这样就能有效地屏蔽内部的细节,免得客户端去调用A模块的接口时,发现了一些不需要它知道的接口,这会造成“接口污染”。 比如a2、a3方法就不需要让客户端知道,否则既暴露了内部的细节,又让客户端迷惑。对客户端来说,他可能还要去思考a2、a3方法用来干什么呢?其实a2、a3方法是对内部模块之间交互的,原本就不是对子系统外部的,所以干脆就不要让客户端知道。 (4)Facade的方法实现 Facade的方法实现中,一般是负责把客户端的请求转发给子系统内部的各个模块进行处理,Facade的方法本身并不进行功能的处理,Facade的方法的实现只是实现一个功能的组合调用。 当然在Facade中实现一个逻辑处理也并无不可,但是不建议这样做,这不是Facade的本意,也超出了Facade的边界。 3.3.3 外观模式的优缺点 l 松散耦合 l 简单易用 l 更好的划分访问层次 l 过多的或者是不太合理的Facade也容易让人迷惑,到底是调用Facade好呢,还是直接调用模块好。 3.3.4 思考外观模式1:外观模式的本质 外观模式的本质:封装交互,简化调用。 Facade封装了子系统外部和子系统内多个模块的交互过程,从而简化外部的调用。通过外观,子系统为外部提供一些高层的接口,以方便它们的使用。 2:对设计原则的体现 外观模式很好的体现了“最少知识原则”。 如果不使用外观模式,客户端通常需要和子系统内部的多个模块交互,也就是说客户端会有很多的朋友,客户端和这些模块之间都有依赖关系,任意一个模块的变动都可能会引起客户端的变动。 使用外观模式过后,客户端只需要和外观类交互,也就是说客户端只有外观类这一个朋友,客户端就不需要去关心子系统内部模块的变动情况了,客户端只是和这个外观类有依赖关系。 这样一来,客户端不但简单,而且这个系统会更有弹性。当系统内部多个模块发生变化的时候,这个变化可以被这个外观类吸收和消化,并不需要影响到客户端,换句话说就是:可以在不影响客户端的情况下,实现系统内部的维护和扩展。 3:何时选用外观模式 建议在如下情况中,选用外观模式:
3.3.5 相关模式 l 外观模式和中介者模式 l 外观模式和单例模式 l 外观模式和抽象工厂模式 本文链接:研磨设计模式之外观模式(Facade)(模式讲解),转自:http://sishuok.com/forum/blogPost/list/5064.html | |||||
本站采用创作共用版权 CC BY-NC-ND/2.5/CN 许可协议
如非特别注明,本站内容均为 领悟书生原创,转载请务必注明作者和原始出处。 本文地址: http://www.656463.com/article/reQ3y2.htm |
研磨设计模式之外观模式(Facade)(模式讲解)
最新推荐文章于 2020-12-18 20:21:54 发布