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

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

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

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


中介者模式
  • Mediator:中介者,实际上可以作为一个抽象类或接口,用以定义一个中介者需要实现的方法,如记录变更、响应变更、增减Colleague等;
  • ConcreteMediator:具体中介者,实现了中介者的方法,明确应该如何进行各项操作;
  • Colleague:协同者,一般是一个抽象类或接口,能够返回一个Mediator对象;
  • ConcreteColleague:具体协同者,实现了Colleague的方法,并且根据实际情况与Mediator进行交互;

中介者

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

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. 观察者模式中,观察者的增加不会影响被观察者的行为;中介者模式中,协同类的增加,势必会影响中介者的行为;

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

牺牲小我,完成大我

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

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

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,294评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,493评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,790评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,595评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,718评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,906评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,053评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,797评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,250评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,570评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,711评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,388评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,018评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,796评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,023评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,461评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,595评论 2 350

推荐阅读更多精彩内容