Bootstrap

7.7 中介者模式(Mediator Pattern)

一. 定义

在现实生活中,常出现多个对象之间存在复杂的交互关系,这种交互关系常常是"网状结构",要求每个对象都必须知道它需要交互的对象.如:每个人必须记住他所有朋友的电话,若朋友中有人的电话变了,他必须让其他所有朋友一起修改,即“牵一发而动全身"。若能把这种“网状结构”改为“星形结构”将大大降低它们之间的“耦合性”,这时需要找一个“中介者”,如上问题只要在网上建立一个每个朋友都可以访问的“通信录”即可解决

中介者模式(Mediator Pattern)

1) 用一个中介对象来封装一系列的对象交互,中介者使各对象无需显示地相互引用,从而使其耦合松散,可独立改变它们之间的交互;

2) 中介者模式又叫调停模式,属于行为模式,它是迪米特法则的典型应用;

3) 比如MVC模式,C(Controller) 是M(Model) 和 V(View) 的中介者,在前后端交互时起到中间人作用;

二. 特点

1. 优点

    1) Mediator的出现减少了各个Colleague之间的藕合,使得可以独立地改变和复用各个Colleague和Mediator;

    2) 将对象间的一对多关联转变为一对一的关联,提高系统的灵活性,使得系统易于扩展与维护;

2. 缺点

由于Mediator中包含所有的Colleague对象,所有控制都在Mediator的sendMessage函数中实现,使得中介者过于复杂。

三. 应用场景

1. 当对象间存在复杂的网状结构关系而导致依赖关系混乱且难以复用时 (通信较为复杂);

2. 当想创建一个运行于多个类之间的对象,有不想生成新的子类时;

四. 模式的结构

1.中介者模式结构图

2.中介者模式角色及职责

   1) Mediator(抽象中介者): 定义了同事对象注册到中介者对象与转发同事对象信息的接口;

   2) ConcreteMediator(具体中介者): 实现抽象方法,使用一个HashMap对具体同事类进行管理,并接受同事对象消息完成相应任务;

   3) Colleague(抽象同事类): 保存中介者对象,提供同事对象交互的抽象方法,实现所有相互影响的同事类的公共功能。

   4) ConcreteColleague(具体同事类): 只知自己的行为,而不知其他同事行为,当需与其他同事交互时,由中介者对象负责后续交互;

五. 模式的实现

0. 项目需求-智能家庭项目:

1)智能家庭包括各种设备, 闹钟、咖啡机、电视机、窗帘等

2)主人要看电视时: 各个设备可协同工作,自动完成看电视的准备工作,流程为:

闹钟响起->咖啡机开始做咖啡->窗帘自动落下 ->电视机播放 ->做好咖啡 -> 关闭电视-> 拉起窗帘

1.传统方案解决

闹钟响起-通知->咖啡机开始做咖啡-通知->窗帘自动落下-通知->电视机播放 -通知->做好咖啡 -通知->关闭电视 -通知->拉起窗帘

1)当各电器对象有多种状态改变时,相互之间的调用关系会比较复杂,各电器你中有我,我中有你,不利于松耦合;

2)各电器对象间所传递的消息(参数),容易混乱;

3)当系统增加一个新的电器对象时,或执行流程改变时,代码的可维护性、扩展性都不理想,考虑使用中介者模式;

2.中介者模式

0> 中介者模式-智能家庭的操作流程

1)创建ConcreteMediator 具体中介实现类对象;

2)根据电器类创建各个同事类对象(子类电器),如: Alarm、CoffeeMachine、TV...

3)在创建同事类对象的时候,就直接通过构造器,加入到ColleagueMap;

4)同事类对象,可调用sendMessage(),最终会去调用ConcreteMediator的 getMessage();

5)getMessage 会根据接收到的同事对象发出的消息来协调,调用其他的同事对象;

6)可以看到getMessage()是核心方法,完成相应的任务;

1> 实例结构图

2> 相关代码实现

object MediatorClient {
    @JvmStatic
    fun main(args: Array<String>) {
        //创建一个中介者对象
        val mediator=ConcreteMediator()
        //创建Alarm 并加入到ConcreteMediator 对象的 HashMap
        val alarm =Alarm(mediator)
        CoffeeMachine(mediator)
        Curtains(mediator)
        TV(mediator)
        //让闹钟发出消息
        alarm.sendAlarm()
    }
}
//抽象中介者
abstract class Mediator {
    //将一个中介者对象加入到一个集合中
    abstract fun register(colleague: Colleague)


    //接收消息,具体的同事对象发出
    abstract fun getMessage(colleagueName: String, stateChange: Int)
}
//具体的中介者类
class ConcreteMediator : Mediator() {
    //集合, 放入所有的同事对象
    private var colleagueMap: HashMap<String, Colleague> = HashMap()
    //将各个具体同事类注册到HashMap中 进行管理
    override fun register(colleague: Colleague) {
        colleagueMap[colleague.name] = colleague
    }
    /**
     * 具体中介者的核心方法
     * 1.根据得到的消息,完成对应任务
     * 2.中介者在这个方法中,协调各个具体的同事对象,完成任务;
     */
    override fun getMessage(colleagueName: String, stateChange: Int) {
        when (colleagueMap[colleagueName]) {
            is Alarm -> {
                (colleagueMap["CoffeeMachine"] as CoffeeMachine?)?.startCoffee()
            }
            is CoffeeMachine -> { //咖啡通知
                if (stateChange == 0) {
                    (colleagueMap["Curtains"] as Curtains?)?.downCurtains()
                } else {
                    (colleagueMap["TV"] as TV?)?.stopTV()
                    (colleagueMap["Curtains"] as Curtains?)?.upCurtains()
                }
            }
            is Curtains -> { //如果是窗帘发出的消息 在这里处理
                (colleagueMap["TV"] as TV?)?.startTV()
            }
            is TV -> { //如果是TV 发出的消息 在这里处理
                (colleagueMap["CoffeeMachine"] as CoffeeMachine?)?.finishCoffee()
            }
        }
    }
}
//抽象同事类
abstract class Colleague (var mMediator:Mediator){
    var name: String = this.javaClass.simpleName
    fun getMediator():Mediator{
        return mMediator
    }
    abstract fun sendMessage(stateChange:Int =0)
}
//具体同事类 - 闹铃
class Alarm (mMediator:Mediator):Colleague(mMediator){
    init {
        //在创建Alarm同事对象时,将自己放入到ConcreteMediator 对象中[集合]
        mMediator.register(this)
    }


    fun sendAlarm() {
        sendMessage()
    }
    override fun sendMessage(stateChange: Int) {
        //调用中介者对象的getMessage()
        getMediator().getMessage(name,stateChange)
    }
}
//具体同事类 - 咖啡机
class CoffeeMachine (mMediator:Mediator):Colleague(mMediator){
    init {
        mMediator.register(this)
    }


    fun startCoffee() {
        println("at this point to start making Coffee")
        sendMessage(0)
    }


    fun finishCoffee(){
        println("After 5 minutes!")
        println("Coffee is Ok!")
        sendMessage(1)
    }
    override fun sendMessage(stateChange: Int) {
        getMediator().getMessage(name,stateChange)
    }
}
//具体同事类 - 窗帘
class Curtains (mMediator:Mediator):Colleague(mMediator){
    init {
        //在创建Alarm同事对象时,将自己放入到ConcreteMediator 对象中[集合]
        mMediator.register(this)
    }


    fun downCurtains() {
        println("at this point to draw down the curtain")
        sendMessage()
    }


    fun upCurtains() {
        println("at this point to hold the curtain")
    }
    override fun sendMessage(stateChange: Int) {
        //调用中介者对象的getMessage()
        getMediator().getMessage(name,stateChange)
    }
}
//具体同事类 - 电视
class TV(mMediator: Mediator) : Colleague(mMediator) {
    init {
        mMediator.register(this)
    }


    fun startTV() {
        println("at this point to start TV")
        sendMessage()
    }


    fun stopTV() {
        println("at this point to stop TV")
    }


    override fun sendMessage(stateChange: Int) {
        getMediator().getMessage(name, stateChange)
    }
}

程序运行结果

at this point to start making Coffee
at this point to draw down the curtain
at this point to start TV
After 5 minutes!
Coffee is Ok!
at this point to stop TV
at this point to hold the curtain

六.中介模式与外观模式的区别

1.外观模式是结构型模式,中介者模式是行为型模式;

2.外观模式是对子系统提供统一的接口,中介者模式是用一个中介对象来封装一系列同事对象的交互行为;

3.外观模式协议是单向,中介者模式协议是双向。

4.外观模式所有的请求处理都委托给子系统完成,而中介者模式则由被具体中介者协调同事类和具体中介者本身共同完成业务。

;