模式产生的背景
1、沉重的网络负担
在没有SessionBean的时候,客户端直接同底层的EntityBean进行交互,形成的是一种具有紧密耦合的硬编码机制,对于远程的客户来说,还附加了沉重的网络交互负担,具体的交互图如下:
在上面的图中,我们假设客户是通过网络对EntityBean的访问,如果EntityBean中有4个字段ABCD,客户要进行字段ABCD的值的设置,就要进行4次网络的传输,我们知道,一个客户要远程与EntityBean交互,就要经过如下的操作:
这样一来,每次进行一次字段ABCD的设定,都要经过4次网络交互,网络的速度一直就是分布式的一个瓶颈,如此沉重的负担毫无疑问会成为项目的拦路虎。
期待的解决方案:如果一次把信息通过网络传输过去,4个字段的设置都在本地服务中进行,就会较少75%的网络负担。
2、严重的不一致错误
我们再看看上面的这个模型,上面的模型有时候(概率也许非常小)会导致数据的不一致,例如,我们设置了字段AB,当设置字段C的时候,网络突然中断了,怎么办?
网络中断就意味着客户虽然设置了AB,却没有办法设置CD,如果CD和AB是相关联的,例如A代表账号,B代表用户名,C代表存款余额,D代表日期,当账号和用户名都改了,本来存款和日期也应该一并修改,但是网络的中断破坏了数据的这种一致性,这无论对用户还是对银行都是一种威胁。
期待的解决方案:如果网络出现异常后,远程服务器能够进行数据的rollback,那么这种危险的不一致问题就有可能得到解决。
3、硬编码导致的高耦合
我们再回头看看上面的模型,我们会发现,如果EntityBean由于某种原因需要改动,那么客户端的代码也必须进行修改,因为客户端是对EntityBeanAPI的硬编码,同时我们也很清楚,客户的需求是多变的,这种高耦合会使我们的项目很快破产。
期待的解决方案:如果能够做到层次的分离,就如同数据库中的外模式、模式、内模式一样,那么就可以克服高耦合,提高系统的健壮性和灵活性。
当然,在实际的应用中,还可能会有这样那样的问题,但是上面的这3个问题就足以促使我们去使用Façade模式。
Façade模式的框架结构
在使用Façade模式之前,我们先来看一下什么是Façade模式(中文名:门面模式、外观模式)。
我们先举一个现实中的例子:新生报道。我们都有过去学校作为新生报道的经历,我们先接到通知,然后坐火车/汽车/自行车,到大学校门口,找新生报道的地点,交上资料,在新生接待处登记,然后去交费处领取交费表单,填写后交费,拿着交费单据去核实处盖章,拿着这些收据返回新生接待处,然后……
这里我们可以看到,新生要和下面的这些人打交道:
售票员:买火车票/汽车票(如果你骑自行车/走路,这一步可以省略:)
新生接待员:你要报道,自然就要找他。
收费人员:你的学费、住宿费就是通过他向“万恶”的学校提交。
核实人员:你还要向他领取收据。
其实,我们知道真正报道的时候,总会有一些意想不到的问题,这些都要我们自己去解决,如果你没有一点经验,恐怕其中还会有一些挫折:)
面向如此繁琐的事情,我们总是觉得不爽,如果我们不去和他们打交道,有专门的人员帮我们负责这些事情,那是再好不过的了,赫赫,这个不用担心了,聪明的父母早就想好了:送小孩子去!
如今的问题变得简单多了,你只要和你父母打交道,即便你对外界了解得不多也不会有什么障碍----有父母呢,怕什么?:)
在这里,我们不知不觉的用到了一个法则:Law Of Demeter(中文名:迪米特法则),一个模式:Façade。
迪米特法则最初是由Han Holland1987年在美国Northeastern University做一个名为Demeter的项目时提出来的,这个法则有以下几个表达方式:
1、只和你的朋友们通信。我们上面的例子就是只和父母通信。
2、不要和陌生人讲话。有父母在我们身边,还有必要和陌生人讲话么?除非你这个人特爱交朋友,那样的话算我一个:)
3、每一个软件单位对其他的单位都只有最少的知识,而且仅局限于那些与本单位密切相关的软件单位。嗯,这个作为一个“两耳不闻窗外事,一心只读圣贤书”的学生,恐怕再适合不过了(指的是我们那时候的高中生,现在的高中生,哎….)
聪明的您一定看出来了,我们举的例子对这个原则是在适合不过了。其实,
Façade模式只不过是这个原则的一个应用罢了,我们来看一下Façade模式的结构图:
我们从上面的图中可以清楚的看到,没有采用Façade模式的系统极其复杂,元素之间的沟通非常困难,因为你要对周围的元素非常了解,换句话说,你要有足够的知识和经验(但是在如今的软件开发中,知识更新如此迅速,要做到这一点很难,不过网络承担起了Façade的作用)。采用了Façade模式的系统看起来非常的整洁和清爽,元素不需要对其他的元素有非常的了解,只要对Façade元素了解即可,其他的任务就有Façade一人去做吧。
Façade模式的优点和缺点
按照惯例,我们先说优点,再说缺点:
1、SessionBean的产生,较少了网络负载。
对于最初的模型,我们可以改进如下:
这样,我们在客户层和EntityBean层,放置了一个中间层Façade,Façade就是这里的SessionBean,SessionBean可以和EntityBean运行在同一个JVM上的相同的容器中,如此一来,SessionBean就可以借助EntityBean的本地接口,屏蔽掉耗资巨大的远程调用,实现高效处理。客户只需要远程访问一次Façade,就可以完成4个字段的设置工作。
1、SessionBean把一致性工作进行了转接。
在上面我们提到了,在没有Façade情况下,网络如果发生错误,就有可能导
致数据的不一致。这个问题产生的根源就在于EntityBean只是负责数据逻辑(Data logic),对于业务逻辑一无所知,自然也就没有办法进行回滚。
我们加上了一个Façade---SessionBean,就是来负责业务逻辑,SessionBean很清楚那些情况应该加锁,哪些情况应该回滚,把这些操作当作一个事务,然后把事务的处理工作通过描述符告诉容器去控制。
如此一来既保证了ACID,又减轻了程序员的工作,并且把业务逻辑与数据逻辑分开,是开发流程更加的清晰,工程进度自然加快。
2、SessionBean以修改为己任
如果没有Façade,客户代码不得不硬编码进EntityBean,如果EntityBean
发生了修改,哪怕就只是一点点,客户端恐怕就要大动干戈。对此,作为开发者显然不能够接受,只有遵循“开闭原则”,才能够满足要求。换句话说,你不是想修改么,没问题,不过条件有一个:你改你的代码,但是不要影响到我。
怎么样才能够做到不影响客户的代码呢?加一个中间层,这个位置正好有SessionBean来顶替,SessionBean提供的是一个业务接口,处理业务逻辑,EntityBean的改变只会影响到和他紧密联系的SessionBean,“Trouble stops here”
这就是SessionBean的至理名言虽然业务逻辑内部有所变动,但他不会反映到接口上来,这也算是ISP的一个应用吧。
接口和实现的分离,降低了系统与客户的耦合性,使得层次结构更为突出,消除了令人头疼的循环依赖。
这还有一个好处就是可移植性增强,由于与客户代码的分离,使得模块化程度增高,独立性增强,可移植性也随之增加。
缺点:
虽然SessionBean又如此众多的优点,但是也有一个致命的缺点:不符合开闭原则。所谓的开闭原则是软件工程里面一个最基本的原则:对扩展开放,对修改关闭。换句话说,你的系统可以提供新的功能模块而不必进行修改。
由于SessionBean与客户端直接交互,客户端的代码势必要硬编码进业务逻辑,如此一来,一旦业务逻辑模块发生变动(增加/删除)势必带来客户端代码的中断。
期待的解决方案:独立于客户端,真正达到“热拔插”。
bw:初次写设计模式方面的东东,参考了《ejb 设计模式》