设计模式系列之「中介者模式」

小Y在文章开始之前先回顾一下历史:三省六部制是西晋以后长期发展形成,至隋朝正式确立,唐朝进一步完善的一种政治制度,反映了中国古代君主专制中央集权制度的进一步完善。那么小Y今天的主题就来了—如何最大实现“一省六部”(尚书省、吏部、户部、礼部、兵部、刑部、工部)的效能,Action。

一、前提

尚书省管属下的六部之间相互协调工作,来张图展示一下这错综复杂、爱恨情仇的关系。


为了文章的简洁,小Y不得不裁减部门了,把“一省六部”直接缩减为“一省三部”。


三个部门相互依赖的同时它们也有着自己的职能,小Y就有失偏颇地概括了一下:

  • 户部:管理钱财。
  • 兵部:掌管兵权。
  • 工部:掌管营造工程事项。

二、情景再现

1.天灾造成百姓流离失所,饿殍满地,这下户部麻烦了,心想着责任不能我一个人担啊,死都要拉个垫背的。

  • 对兵部说:饥民太多,恐防出现暴乱,需要军队镇压。

  • 对工部说:灾害损毁房屋太多,需要你们来规划重建。

2.不长眼睛的蛮夷族要攻打天朝,兵部这下就坐不住了,立马找来工部和户部。

  • 对工部说:蛮夷族的战斗力太强悍了,需要通过一些防御工事抵御,这事就交给你们了。

  • 对户部说:要想打胜仗,士兵首先要吃得饱穿得暖,吃穿的钱粮这个重任就非你们莫属了。

3.皇帝老爷的妃子多了,行宫要大批大批的建,工部就抱怨了,为毛皇帝这毛快活就要累死我们,不行,有苦同吃,有难各自飞,这才是兄弟嘛。

  • 对兵部说:陛下要求大规模建行宫,为陛下服务的机会到了哈,调遣大批士兵给我当苦力吧。

  • 对户部说:行官需要设计精美,需要花费的银子不少,需要你们搜刮多点民脂民膏。

三、出谋划策

  • 方案一:尚书省只挂个管理牌就可以,对下面六个部门的工作不干预,爱咋干咋干,关键时刻给我功劳就好。

  • 以尚书省为中心,底下六个部门在工作上不直接进行交流,统一经过尚书
    省(中介者模式)。

四、来波广告

1.中介模式的定义

用一个中介对象封装一系列的对象交互,中介者使各对象不需要显示地相互作用,从而使其耦合松散,而且可以独立地改变它们之间的交互。

2.中介模式的角色介绍

  • Mediator 抽象中介者角色
    抽象中介者角色定义统一的接口,用于各同事角色之间的通信。

  • Concrete Mediator 具体中介者角色
    具体中介者角色通过协调各同事角色实现协作行为,因此它必须依赖于各个同事角色。

  • Colleague 同事角色
    每一个同事角色都知道中介者角色,而且与其他的同事角色通信的时候,一定要通过中介者角色协作。每个同事类的行为分为两种:一种是同事本身的行为,比如改变对象本身的状态,处理自己的行为等,这种行为叫做自发行为,与其他的同事类或中介者没有任何的依赖;第二种是必须依赖中介者才能完成的行为,叫做依赖方法。

3.中介模式的使用场景

  • 在面向对象的编程中,对象和对象之间必然会有依赖关系。

  • 中介者模式适用于多个对象之间紧密耦合的情况,紧密耦合的标准是:在类图中出现了蜘蛛网状结构。

五、方案的实施

1.方案一

发生事情各个部门自行商量解决。

①户部

public class Department {

    public void dealDisaster(){
        System.out.println("户部:专挑轻活,其他的找别人干去。");
        //需要工部规划重建
        Ministry ministry=new Ministry();
        ministry.selfFunction();
        //需要兵部调兵遣将镇压灾民
        Defense defense=new Defense();
        defense.selfFunction();

    }

    public void selfFunction(){
        System.out.println("户部:要钱没问题,我尽量搜刮点民脂民膏。");
    }
}

②兵部

public class Defense {

    public void fight(){
        System.out.println("我只出人,剩下的找别人干去。");
        //需要户部搜刮民脂民膏
        Department department=new Department();
        department.selfFunction();
        //需要工部给图纸建造防御工事
        Ministry ministry=new Ministry();
        ministry.selfFunction();
    }

    public void selfFunction(){
        System.out.println("兵部:要人没问题,我尽量抓多几个壮丁");
    }
}

③工部

public class Ministry {

    public void buildPalace(){
        System.out.println("工部:我只画图纸,其他的找别人干去。");
        //需要户部出钱
        Department department=new Department();
        department.selfFunction();
        //需要兵部调兵遣将加入建造
        Defense defense=new Defense();
        defense.selfFunction();
    }

    public void selfFunction(){
        System.out.println("工部:要建筑图纸没问题,我尽量复制多几份");
    }
}

④Client

public class Client {
    public static void main(String[] args) {
        //发生天灾了,户部麻烦了,需要解决问题
        Department department=new Department();
        department.dealDisaster();
        //要打仗了,兵部的活来了
        Defense defense=new Defense();
        defense.fight();
        //皇帝发话了,工部赶紧建行宫
        Ministry ministry=new Ministry();
        ministry.buildPalace();
    }
}

输出的结果为:

//发生天灾了,户部麻烦了,需要解决问题
户部:专挑轻活,其他的找别人干去。
工部:要建筑图纸没问题,我尽量复制多几份。
兵部:要人没问题,我尽量抓多几个壮丁。

//要打仗了,兵部的活来了
兵部:我只出人,剩下的找别人干去。
户部:要钱没问题,我尽量搜刮点民脂民膏。
工部:要建筑图纸没问题,我尽量复制多几份。

//皇帝发话了,工部赶紧建行宫
工部:我只画图纸,其他的找别人干去。
户部:要钱没问题,我尽量搜刮点民脂民膏。
兵部:要人没问题,我尽量抓多几个壮丁。

三个部门遇到问题都相互协调解决了,没出什么幺蛾子,尚书省也照样得到功劳奖励。从上面的例子发现这三个类是彼此关联的,每个类都与其他两个类产生了关联关系。这样子缺点就暴露出来了,它们彼此关联越多,耦合性越大,要想修改一个就得修改一片,这不是面向对象设计所期望的,上面的例子还是仅三个部门的情况,如果实现上图的六部之间的协调关系,维护起来都要吐血而亡,果断抛弃。

2.方案二(中介者模式)

UML实现
①抽象中介者(尚书省)
public abstract class AbstractMediator {

    protected Department department;
    protected Defense defense;
    protected Ministry ministry;

    public AbstractMediator() {
        department = new Department(this);
        defense=new Defense(this);
        ministry=new Ministry(this);
    }
    
    //中介者最重要的方法叫做事件方法,处理多个对象之间的关系
    public abstract void dealThing(int code);
}
②具体中介者
public class Mediator extends AbstractMediator{

    public static final int DEPARTMENT_CODE=1;
    public static final int DEFENSE_CODE=2;
    public static final int MINISTRY_CODE=3;

    @Override
    public void dealThing(int code) {
        switch (code){
            case DEPARTMENT_CODE:
                this.dealDisaster();
                break;
            case DEFENSE_CODE:
                this.fight();
                break;
            case MINISTRY_CODE:
                this.buildPalace();
                break;
        }
    }
    //户部处理天灾
    private void dealDisaster(){
        System.out.println("户部:专挑轻活,其他的找别人干去。");
        super.ministry.selfFunction();
        super.defense.selfFunction();
    }
    //兵部打仗
    private void fight(){
        System.out.println("兵部:我只出人,剩下的找别人干去。");
        super.department.selfFunction();
        super.ministry.selfFunction();
    }
    //工部建行宫
    private void buildPalace(){
        System.out.println("工部:我只画图纸,其他的找别人干去。");
        super.department.selfFunction();
        super.defense.selfFunction();
    }
}
③抽象部门类
public abstract class AbstractColleague {
    protected AbstractMediator abstractMediator;

    public AbstractColleague(AbstractMediator abstractMediator) {
        this.abstractMediator = abstractMediator;
    }
}
④户部
public class Department extends AbstractColleague{

    public Department(AbstractMediator  abstractMediator) {
    super(abstractMediator);
    }

    public void dealDisaster(){
        super.abstractMediator.dealThing(Mediator.DEPARTMENT_CODE);
    }

    public void selfFunction(){
        System.out.println("要钱没问题,我尽量搜刮点民脂民膏。");
    }
}
⑤兵部
public class Defense extends AbstractColleague{

    public Defense(AbstractMediator abstractMediator) {
        super(abstractMediator);
    }

    public void fight(){
        super.abstractMediator.dealThing(Mediator.MINISTRY_CODE);
    }

    public void selfFunction(){
        System.out.println("兵部:要人没问题,我尽量抓多几个壮丁");
    }
}
⑥工部
public class Ministry extends AbstractColleague{

    public Ministry(AbstractMediator abstractMediator) {
        super(abstractMediator);
    }

    public void buildPalace(){
        super.abstractMediator.dealThing(Mediator.MINISTRY_CODE);
    }

    public void selfFunction(){
        System.out.println("要建筑图纸没问题,我尽量复制多几份");
    }
}
⑦Client
public class Client {
    public static void main(String[] args) {
        AbstractMediator abstractMediator=new Mediator();
        //发生天灾了,户部麻烦了,需要解决问题
        Department department=new Department(abstractMediator);
        department.dealDisaster();
        //要打仗了,兵部的活来了
        Defense defense=new Defense(abstractMediator);
        defense.fight();
        //皇帝发话了,工部赶紧建行宫
        Ministry ministry=new Ministry(abstractMediator);
        ministry.buildPalace();
    }
}

输出的结果为:

//发生天灾了,户部麻烦了,需要解决问题
户部:专挑轻活,其他的找别人干去。
工部:要建筑图纸没问题,我尽量复制多几份。
兵部:要人没问题,我尽量抓多几个壮丁。

//要打仗了,兵部的活来了
兵部:我只出人,剩下的找别人干去。
户部:要钱没问题,我尽量搜刮点民脂民膏。
工部:要建筑图纸没问题,我尽量复制多几份。

//皇帝发话了,工部赶紧建行宫
工部:我只画图纸,其他的找别人干去。
户部:要钱没问题,我尽量搜刮点民脂民膏。
兵部:要人没问题,我尽量抓多几个壮丁。
(1)建立了两个抽象类AbstractMediator和AbstractColeague,每个对象只是与中介者Mediator之间产生依赖,与其他对象之间没有直接关系。
(2)中介者Mediator定义了多个private方法,其目的是处理各个对象之间的依赖关系,就是说把原有一个对象要依赖多个对象的情况移到中介者的private方法中实现。
(3)在场景类中增加了一个中介者,然后分别传递到三个同事类中,三个类都具有相同的特性:只负责处理自己的活动(行为),与自己无关的活动就丢给中介者处理。
(4)在多个对象依赖的情况下,通过加入中介者角色,取消了多个对象的关联或依赖关系,减少了对象的耦合性。

六、中介者模式优缺点

1.优点

中介者模式的优点就是减少类间的依赖,把原有的一对多的依赖变成了一对一的依赖,同事类只依赖中介者,减少了依赖,当然同时也降低了类间的耦合。

2.缺点

中介者模式的缺点就是中介者会膨胀得很大,而且逻辑复杂,原本N个对象直接的相互依赖关系转换为中介者和同事类的依赖关系,同事类越多,中介者的逻辑就越复杂。

七、简单对比观察者模式和中介者模式的区别

1.多个对象之间需要交互,那么这些对象间的交互就会形成网状结构。引入中介者,各对象根本不知道其它对象的存在,他们只需要把信息发送给中介者,由中介者来控制把信息传递给哪些对象。
2.观察者依赖于被观察者的状态改变,两者之间是需要交互的。

八、总结

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

推荐阅读更多精彩内容