设计模式之中介模式Mediator Pattern——所有编程框架都会使用的模式

中介模式的中文翻译非常形象。大家买房子要中介,中介做的什么事情呢?我们先不会回答这个问题。而是反问依据,如果没有中介,我们买房子的场景会是怎样?

  1. 满世界找有可能买房子的房东?可能同时要跟20个房东打交道,跟房东约时间可真是看天气、看运气的事情
  2. 房产交易要签合同?我们要跟房东拟定合同?还要一起房地产交易中心做网签备案
  3. 如果全款购房的话,还稍微简单点。如果钱不够想分期怎么办?购房者还要跟银行打交道,可能还不止一家银行,因为各家银行的放款条件,贷款额度、贷款利率和贷款期限可能有所不同

其实上面所说的还可能只是其中一角,这也是为什么绝大部分人都选择中介来帮忙购房或中介来托管房屋,进行售房。有了中介,世界就变得如此简单,比如对于购房者而言,只要关注:

  1. 告诉中介我要买房,告之购房要求、可用时间,然后等着看房就好了
  2. 房子看重了,要贷款,去中介那里,带上身份证,签个合同就结束了

当然,对于售房者而言,也是一样的简单。因为中介为我们屏蔽了购房过程中的所有角色:购房者 * 售房者 * 银行 * 房地产交易中心,每个角色关注自己的诉求和需要做的事情即可。

这就是中介者模式的魅力。还有很多这样的例子可以拿来说说,比如:

  • 机场的航站塔台对飞机的调度,飞机之间不需要互相通信
  • 一个页面上的复杂表单可能有几十个组件:TextInput/Checkbox/Button/Select/Radio,通常他们是不需要关注彼此的,只要将变更告知整个表单组件以及接受表单组件的通知即可

解决问题&适用场景:

从上面的例子,我们能够看到,中介模式很实用在有多个角色之间,交互复杂且混乱的场景下使用。中介模式能够把网状的交互,编程星形的交互。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XkRPzQvE-1654791906657)(../../../assets/image-20220609235203024.png)]在这里插入图片描述

代码结构&示例

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QDhabauL-1654791600976)(../../../assets/structure.png)]

结构其实比较简单,几个关键的类:

  • Component:需要进行解耦的对象,上图各个Component最好继承自一个基类,这样会便于中介类做一些抽象和统一管控;每个Component都持有中介对象的引用,有事情发生时,调用notify就好,参数就是Component对象自己就好
  • Meditator:中介,一般来讲中介类只有一个notify方法就足够了。中介对象持有所有Component的引用,他会收到各个Component对象发来的通知(notify),他知道该怎么协调,下一步该做什么。某种角度,它就是“上帝”,至于说怎么让上帝不至于变得过于复杂,是另外一个需要讨论的命题
  • ConcreteMediator:具体的中介实现,不同的背景和目的下,实现也会有所不同,比如上面的表单例子中,不同的表单,需要调度的组件、校验、联动规则、提交后的去向等,都会有所不同

代码上我们就以上面的星形图来做示例:

  • Component
// abstract Component
public abstract class Colleague {
    public abstract void onEvent(Mediator mediator);
}

// Component Alarm
public class Alarm extends Colleague {

    @Override
    public void onEvent(Mediator mediator) {
        mediator.doEvent("alarm");
    }

    public void doAlarm() {
        System.out.println("doAlarm()");
    }
}

// Component CoffeePot
public class CoffeePot extends Colleague {
    @Override
    public void onEvent(Mediator mediator) {
        mediator.doEvent("coffeePot");
    }

    public void doCoffeePot() {
        System.out.println("doCoffeePot()");
    }
}

// Component Calender
public class Calender extends Colleague {
    @Override
    public void onEvent(Mediator mediator) {
        mediator.doEvent("calender");
    }

    public void doCalender() {
        System.out.println("doCalender()");
    }
}

// Component Sprinkler
public class Sprinkler extends Colleague {
    @Override
    public void onEvent(Mediator mediator) {
        mediator.doEvent("sprinkler");
    }

    public void doSprinkler() {
        System.out.println("doSprinkler()");
    }
}

  • Mediator
// Mediator
public abstract class Mediator {
    public abstract void doEvent(String eventType);
}

// ConcreteMediator
public class ConcreteMediator extends Mediator {
    private Alarm alarm;
    private CoffeePot coffeePot;
    private Calender calender;
    private Sprinkler sprinkler;

    public ConcreteMediator(Alarm alarm, CoffeePot coffeePot, Calender calender, Sprinkler sprinkler) {
        this.alarm = alarm;
        this.coffeePot = coffeePot;
        this.calender = calender;
        this.sprinkler = sprinkler;
    }

    @Override
    public void doEvent(String eventType) {
        switch (eventType) {
            case "alarm":
                doAlarmEvent();
                break;
            case "coffeePot":
                doCoffeePotEvent();
                break;
            case "calender":
                doCalenderEvent();
                break;
            default:
                doSprinklerEvent();
        }
    }

    public void doAlarmEvent() {
        alarm.doAlarm();
        coffeePot.doCoffeePot();
        calender.doCalender();
        sprinkler.doSprinkler();
    }

    public void doCoffeePotEvent() {
        // ...
    }

    public void doCalenderEvent() {
        // ...
    }

    public void doSprinklerEvent() {
        // ...
    }
}
  • Client
public class Client {
    public static void main(String[] args) {
        Alarm alarm = new Alarm();
        CoffeePot coffeePot = new CoffeePot();
        Calender calender = new Calender();
        Sprinkler sprinkler = new Sprinkler();
        Mediator mediator = new ConcreteMediator(alarm, coffeePot, calender, sprinkler);
        // 闹钟事件到达,调用中介者就可以操作相关对象
        alarm.onEvent(mediator);
    }
}

输出:

doAlarm()
doCoffeePot()
doCalender()
doSprinkler()

优缺点

Good

  • 遵守单一职责原则,各个组件的职责都可以保持克制和单一
  • 遵守开闭原则,各个组件的代码不需要修改,但是他们的行为的可以通过实现中介类来做扩展
  • 遵守迪米特法则,各个组件之间无需知晓对方的知识,只需要关注和中介的基础交互即可

Bad

  • 组件的可扩展、可维护,是将复杂度转移到中介对象上为代价,因此如果不加控制和设计,中介对象很容已成为一个“上帝对象”,啥都要管,谁都不敢改动

结语

中介模式其实是一个很流行的模式,从它遵守的几个原则就窥见一斑。在该模式下,组件的扩展和维护变得简单,但需要注意的是,要有一个真正的专家(我说的就是个人)来做中介的设计和统筹,并且为了这个专家的知识成为黑洞,甚至公司的负资产,一定要做好文档的记录和backup的培养,要不专家一走,就马上成为一坨可怕的屎山了🤮

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值