SweetDream
高歌一壶新酿酒,醉抱青山不必归。

        门面(Facade)模式和中介者(Mediator)模式有着共同的目的。它们都是调配一组相互耦合的对象的通信。不过门面模式关注的是这组复杂对象如何与外界通信,而中介者模式是调配这组复杂对象之间的通信。

门面(Facade)模式
        当想要为一组具有复杂且全面的接口对象提供一个简单且特定的接口供外界使用时,就可以采用门面模式。
        门面模式理解起来不难,但是要找到合适粒度的门面就不那么容易了。[GOF95]中说:“一个常见的设计目标是使子系统间的通信和相互依赖关系达到最小达到该目标的途径之一就是引入一个门面对象,它为子系统中较一般的设施提供了一个单一而简单的界面。”我觉得,虽然用户不必直接和子系统中的类打交道了,但是通过门面也间接地和它们有所联系(这里可能可以用Adapter模式隔离变化)。门面模式的主要目的我觉得不在于减少依赖关系(如果包括间接依赖),而是简化用户的使用接口。门面模式是有悖于接口隔离原则的。但是话说回来如果门面选择的粒度合适的话那么还是利大于弊的。
 
 门面模式的应用:
        当你要为一个复杂子系统提供一个简单接口时。子系统往往因为不断演化而变得越来越复杂。大多数模式使用时都会产生更多更小的类。这使得子系统更具可重用性,也更容易对子系统进行定制,但这也给那些不需要定制子系统的用户带来一些使用上的困难。Facade可以提供一个简单的缺省视图,这一视图对大多数用户来说已经足够,而那些需要更多的可定制性的用户可以越过Facade层。
        引入Facade将这个子系统与客户以及其他的子系统分离,可以提高子系统的独立性和可移植性。
        当你需要构建一个层次结构的子系统时,使用Facade模式定义子系统中每层的入口点,如果子系统之间是相互依赖的,你可以让它们仅通过Facade进行通讯,从而简化了它们之间的依赖关系。


门面模式的结构:


 门面(Facade)角色:客户端可以调用这个角色的方法。此角色知晓相关的(一个或者多个)子系统的功能和责任。在正常情况下,本角色会将所有从客户端发来的请求委派到相应的子系统去。

 子系统(subsystem)角色:可以同时有一个或者多个子系统。每一个子系统都不是一个单独的类,而是一个类的集合。每一个子系统都可以被客户端直接调用,或者被门面角色调用。子系统并不知道门面的存在,对于子系统而言,门面仅仅是另外一个客户端而已。
     注意,可以用抽象类实现Façade而它的具体子类对应于不同的子系统实现,这可以进一步降低客户与子系统得耦合度。这样,客户就可以通过抽象的Façade类接口与子系统通讯。这种抽象耦合关系使得客户不知道它使用的是子系统得那一个实现。


中介者(Mediator)模式
       用一个中介对象来封装一系列对象(此模式中称为Colleague)交互。中介者使各对象不需要显示地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互(只须改变中介者类)。<<Java与模式>>中有个比较形象的例子,就是中国加入WTO后,与外国的贸易往来都不必和每个国家达成协商,而只要符合WTO的协议就可以了。WTO在这里起了一个中介者的作用。
      考虑一个窗体,其中有很多控件,Button,TextBox,ListBox等,这些控件都是相互作用的,比如如果TextBox中没有字符的话,那么Button的状态就为UnEnable,当改变ListBox的选项时,TextBox中会显示ListBox中所选定的项。如果按常规设计这些对象之间的关系就会变得复杂而且不好管理,没有第三者来组织它们,造成高度的耦合,最坏的情况下,每个对象都要知道其它的对象,可维护性大打折扣;而且要把相互作用的逻辑封装到自己的类中,重用的可能性也就大打折扣了。
        我们可以通过将集体行为封装在一个单独的中介者对象中以避免这个问题。中介者负责控制和协调一组对象间的交互。中介者充当一个中介以使组中的对象不再相互显示引用。这些对象仅知道中介者,从而减少了相互连接的数目。
 
 中介者模式的结构:

 
 Mediator(中介者)
      中介者定义一个接口用于与各同事(Colleague)对象通信。
 ConcreteMediator(具体中介者)
      具体中介者通过协调各同事对象实现协作行为。
      了解并维护它的各个同事。
 Colleague(同事类)
       每一个同事类都知道它的中介者对象。
       每一个同事对象在需与其他的同事通信的时候,仅仅与它的中介者通信。 
      
      协作:同事向一个中介者对象发送和接收请求。中介者在各同事间适当地转发请求以实现协作行为。
      从结构图我们可以看出中介者知道所有同事类,从而才能调度它们,因此可以说中介者模式是将交互的复杂性变成中介者的复杂性。反过来每个同事类都知道它的中介者对象,这样它才能当自己状态改变时通知给中介者,从而影响其它的同事类。(这里有两种实现的方式1.  可以用到Observer模式;2.  在Mediator中定义一个特殊的通知接口,各Colleague在通信时直接调用这个接口并将自身作为一个参数传递给Mediator,使其可以识别发送者。 )。这样的耦合性似乎和Façade模式一样有悖于接口隔离原则的:如果一个同事类的接口改变,那么中介者也将改变,从而使得所有的同事类都要改变。这里是一个循环依赖,每个类接口的改变都可能造成所有类都改变。但是本模式的主要目的之一是简化通信方式,而不是隔离同事类的变化。我们看看GOF描述这个模式的适用性:
        1.一组对象以定义良好(注意这里说了是定义良好,如果同事类需要经常改变接口就要小心了)但是复杂的方式进行通信。产生的相互依赖关系结构混乱且难以理解。
        2.一个对象引用其他很多对象并且直接与这些对象通信,导致难以复用该对象。(一个对象如果和太多的其它对象相关联就很难复用了)
        3.想定制一个分布在多个类中的行为,而又不想生成太多的子类。(比如上面说的改变一个控件的状态就可以引起其它控件的变化)
    
     中介者模式的优点和缺点:
 1.减少子类的生成   Mediator将原本分布于多个对象间的行为集中在一起。改变这些行为只需生成Mediator的子类即可。
 2.它将各Colleague解耦  Mediator有利于各Colleague类间的松耦合。你可以独立的改变和复用各Colleague类和Mediator类。
 3.它简化了对象协议   用Mediator和各Colleague间的一对多的交互来替代多对多的交互。一对多的关系更易于理解。维护和扩展。
 4.它对对象如何协作进行了抽象   将中介作为一个独立的概念并将其封装在一个对象中,使你将注意力从对象各自本身的行为转移到他们之间的交互上来。这有助于弄清楚一个系统中的对象是如何交互的。
 5.它使控制集中化   中介者模式将交互的复杂性变为中介者的复杂性。因为中介者封装了协议,它可能比任何一个Colleague都复杂。这可能使得中介者自身成为一个难于维护的庞然大物。

posted on 2005-12-19 11:38  SweetDream  阅读(2708)  评论(1编辑  收藏  举报