JavaEE 学习专题程序员

Java设计模式之-中介者模式(Mediator)

2017-11-28  本文已影响0人  Mock2052

中介者模式,又叫调停者模式。我看的书里面是叫做调停者的,我个人认为没有“中介者”这个名字容易理解。

中介者模式:在一个庞大系统中,多个类之间需要进行信息的交换,从而引发后续的行为。这个时候为了避免类之间呈网状关联,引入一个中介者用以管理其他类,接收某些类传入的信息,并反映在对应的相应类上,变网状为星状,减少类之间的耦合性。

以上是我对中介者模式的理解,下面我们来看一下在Java语言中,该模式应该如何设计:


中介者模式

中介者

很简单的一个接口,定义了一个用于反馈的方法:

package com.designpattern;

public interface IMediator {
    public void react(AbstractColleague c);
}

协同者

包含一个中介者的实例,为了能够定义构造函数,我将它写成了一个抽象类。请注意,接口不能定义构造函数

package com.designpattern;

public abstract class AbstractColleague {
    protected IMediator mediator;

    public AbstractColleague(IMediator m) {
        mediator = m;
    }

    public final IMediator getMediator() {
        return mediator;
    }
}

具体协同者

我们先来定义两个具体的协同者,他们直接需要进行某些交互的动作,但是由于中介者的存在,他们不必互相了解,只要将自身的变化告诉中介者即可。

ViewColleague
package com.designpattern;

public class ViewColleague extends AbstractColleague {
    public ViewColleague(IMediator m) {
        super(m);
    }

    public void mockClick() {
        System.out.println("View got a click action.");
        getMediator().react(this);
    }

    public void display(String data) {
        System.out.println("View got " + data + " from model.");
    }

    public void prepareShutdown(){
        System.out.println("View knows that: Model gonna shutdown, backup your data.");
    }
}
ModelColleague
package com.designpattern;

public class ModelColleague extends AbstractColleague {

    public ModelColleague(IMediator m) {
        super(m);
    }

    public String whenClick(){
        System.out.println("Model should return some data to view.");
        return "data";
    }

    public void shutdown(){
        System.out.println("Model will shutdown in 5 sec.");
        getMediator().react(this);
    }
}

具体中介者

其实看到我上面两个类的命名之后,大家应该就能猜到我在干什么。我想用中介者模式表现MVC架构,或者也能说我想用MVC来说明中介者模式的作用。

package com.designpattern;

public class ControllerMediator implements IMediator {
    private ViewColleague viewColleague;
    private ModelColleague modelColleague;

    public ControllerMediator setView(ViewColleague v){
        viewColleague = v;
        return this;
    }

    public ControllerMediator setModel(ModelColleague m){
        modelColleague = m;
        return this;
    }

    @Override
    public void react(AbstractColleague c) {
        if (c instanceof ViewColleague) {
            String data = modelColleague.whenClick();
            viewColleague.display(data);
        } else if (c instanceof ModelColleague) {
            viewColleague.prepareShutdown();
        } else {
            System.out.println("Not Supported Class: " + c.getClass().getName());
            // you can also :
            //throw new NotSupportedException();
        }
    }
}

大家可以看到,在中介者中保存了两个Colleague对象,如果说我们现在展示的不是MVC,而是MVVM框架,那么就会有更多的实例保存在终结者中。这个是无法避免的,中介者必须拥有所有的协同者

好的,然后我们来写一个main方法驱动整个代码:

public static void main(String[] args){
        ControllerMediator controller = new ControllerMediator();
        ViewColleague view = new ViewColleague(controller);
        ModelColleague model = new ModelColleague(controller);
        controller.setView(view).setModel(model);

        //view change:
        view.mockClick();

        //model change:
        model.shutdown();
    }

我们先将协同者和中介者进行关联,然后尝试模拟View的变更以及Model的变更。执行main方法,可以看到输出结果如下:

View got a click action.
Model should return some data to view.
View got data from model.
Model will shutdown in 5 sec.
View knows that: Model gonna shutdown, backup your data.

View出现了状态的改变,但它不需要知道有谁需要因此而做什么事情,只需要告诉中介者即可,Model亦然。两者存在着数据和信息的交换,但是又不知道彼此,一个中介者将两者完美地解耦了。

中介者模式和观察者模式

其实在思考和编写这个例子的时候,我一直在想这两个模式的关系。两者虽然很相似,但是理解之后还是能发现有很大区别的:

  1. 观察者模式中,变更发生在被观察者,即中心节点;中介者模式中,变更发生在某一个协同类,而非中心节点-中介类;
  2. 观察者模式中,针对变更的行为由观察者实现;中介者模式中,虽然会使用到协同类的某些方法,但是具体行为顺序和参数则由中介者来确定;
  3. 观察者模式中,由于观察者实现了同一接口,在被观察者看来是一组相同的对象;在中介者模式中,每个协同类虽然一般都会源自某个类或接口,但实际上各司其职,是不同的对象,有着自身独特的方法;
  4. 观察者模式中,观察者的增加不会影响被观察者的行为;中介者模式中,协同类的增加,势必会影响中介者的行为;

以上四点,是我自己能想到的一些区别,其中关于第四点我想多说一点,其实它也就是中介者模式存在的弊端。

牺牲小我,完成大我

中介者模式能够让协同类之间的耦合性消失,但又引出了新的问题:它自己。由于集所有协同类与一身,并且负责担当类之间的调度员和粘合剂,使得中介者自身改动频繁,且难于维护。降低了系统耦合,却将所有复杂度和内聚性融于自身。

因此,合理选择中介者的使用场景和使用粒度非常重要,不需要为了使用设计模式而使用。要让中介者的牺牲是值得的才行。

上一篇下一篇

猜你喜欢

热点阅读