Mediator - 中介者模式

2,272 阅读8分钟

 1. 什么是Mediator模式

Mediator模式(中介者模式)又称为调停者模式。一个模块或者系统,可能由多个对象构成,这些对象之间可能存在互相调用的情况。这样会复杂化对象之间的联系,大量的相互连接使得一个对象似乎不太可能在没有其他对象支持的情况下独立完成工作,久而久之所有的对象将变得像一个不可分割的整体,对系统或模块的任何较大的变动都变得十分的困难。
中介者模式可以降低多个对象和类之间的通信复杂度。这种模式提供了一个中介类,该类通常用于处理不同类之间的通信,降低类之间的耦合度,使代码易于维护。中介者模式属于行为型模式。

通过应用Mediator模式,可以将类与类之间的多对都的关系转化成一对多的关系,从而降低了同事类之间的耦合度,提高可修改性。

2.现实生活中的例子

  • 房产中介
    在毕业生租房的场景中,找房者和房东们可以视为两组同事。在引入中介前后,房东和找房之间的关系如下所示。

  • 公司的零食决策
    方案一: 让同事之间自行交流,直到每个人都掌握其余人的投票信息。
    方案二: 发起一个线上投票,统计票数,每个人都可以看到当前的投票情况。

  • 聊天室
    QQ,微信等聊天平台实际上也是一个“中介者”

3.设计思路

类图

名称说明
Mediator抽象中介者角色定义统一的接口
ConcreteMediator实现了Mediator接口,并且协同Colleague对象之间的交互
Colleague抽象同事类角色,定义了中介者对象的接口,它只知道中介者而不知道其他同事对象
ConcreteColleague具体的同事类,可以通过Mediator与其他Colleague进行交互

(1)通用实现

场景:同事A和同事B通过中介者进行相互通信

//抽象同事类
public abstract class Colleague {

    protected Mediator mediator;

    public void setMediator(Mediator mediator) {
        this.mediator = mediator;
    }

    public abstract void operation();
}
//具体同事类
public class ConcreteColleagueA extends Colleague{

    public void notifyColleagueB() {
        mediator.notifyColleagueB();
    }

    @Override
    public void operation() {
        System.out.println("ColleagueA的一些操作");
    }
}

public class ConcreteColleagueB extends Colleague{

    public void notifyColleagueA() {
        mediator.notifyColleagueA();
    }

    @Override
    public void operation() {
        System.out.print("ColleagueB的一些操作");
    }
}
// 抽象中介者
public abstract class Mediator {

    protected Colleague colleagueA;
    protected Colleague colleagueB;

    public Mediator(Colleague colleagueA, Colleague colleagueB) {
        this.colleagueA = colleagueA;
        this.colleagueB = colleagueB;
    }

    public abstract void notifyColleagueA();
    public abstract void notifyColleagueB();
}
// 中介者实现
public class ConcreteMediator extends Mediator{

    public ConcreteMediator(Colleague colleagueA, Colleague colleagueB) {
        super(colleagueA, colleagueB);
    }

    @Override
    public void notifyColleagueA() {
        if (colleagueA != null) {
            colleagueA.operation();
        }
    }

    @Override
    public void notifyColleagueB() {
        if (colleagueB != null) {
            colleagueB.operation();
        }
    }
}
// 测试类
public class Client {
    public static void main(String[] args) {
        Colleague colleagueA = new ConcreteColleagueA();
        Colleague colleagueB = new ConcreteColleagueB();

        Mediator mediator = new ConcreteMediator(colleagueA, colleagueB);
        colleagueA.setMediator(mediator);
        colleagueB.setMediator(mediator);

        ((ConcreteColleagueA)colleagueA).notifyColleagueB();
        ((ConcreteColleagueB)colleagueB).notifyColleagueA();
    }
}

结果: 两个Colleague类成功通过Mediator进行了通信。

(2)中介者模式的例子

//抽象同事类
abstract class AbstractColleague {  
    protected AbstractMediator mediator;  

    /**既然有中介者,那么每个具体同事必然要与中介者有联系,  
     * 否则就没必要存在于 这个系统当中,这里的构造函数相当  
     * 于向该系统中注册一个中介者,以取得联系  
     */ 
    public AbstractColleague(AbstractMediator mediator) {  
        this.mediator = mediator;  
    }  

    // 在抽象同事类中添加用于与中介者取得联系(即注册)的方法  
    public void setMediator(AbstractMediator mediator) {  
        this.mediator = mediator;  
    }  
}  

//具体同事A  
class ColleagueA extends AbstractColleague {  

    //每个具体同事都通过父类构造函数与中介者取得联系  
    public ColleagueA(AbstractMediator mediator) {  
        super(mediator);  
    }  

    //每个具体同事必然有自己分内的事,没必要与外界相关联  
    public void self() {  
        System.out.println("同事A做自己的事情.");  
    }  

    //每个具体同事总有需要与外界交互的操作,通过中介者来处理这些逻辑并安排工作  
    public void notifyColleagueB() {  
        System.out.println("请求同事B好好工作");  
        super.mediator.execute("ColleagueB", "self");  
    }  
}  

//具体同事B  
class ColleagueB extends AbstractColleague {  

    public ColleagueB(AbstractMediator mediator) {  
        super(mediator);  
    }  

    public void self() {  
        System.out.println("同事B做自己的事情");  
    }  

    public void notifyColleagueA() {  
        System.out.println("请求同事A好好工作.");  
        super.mediator.execute("ColleagueA", "self");  
    }  
} 
// 抽象中介者
abstract class AbstractMediator {  

    //中介者需要保持有若干同事的联系方式  
    protected Hashtable<String, AbstractColleague> colleagues = new Hashtable<String, AbstractColleague>();

    //中介者可以动态地与某个同事建立联系  
    public void addColleague(String name, AbstractColleague c) {  
        this.colleagues.put(name, c);  
    }     

    //中介者也可以动态地撤销与某个同事的联系  
    public void deleteColleague(String name) {  
        this.colleagues.remove(name);  
    }  

    //中介者必须具备在同事之间处理逻辑、分配任务、促进交流的操作  
    public abstract void execute(String name, String method);   
}  

//具体中介者  
class Mediator extends AbstractMediator{  

    //中介者最重要的功能,来回奔波与各个同事之间  
    public void execute(String name, String method) {  

        if("self".equals(method)){  //各自做好分内事  
            if("ColleagueA".equals(name)) {  
                ColleagueA colleague = (ColleagueA)super.colleagues.get("ColleagueA");  
                colleague.self();  
            }else {  
                ColleagueB colleague = (ColleagueB)super.colleagues.get("ColleagueB");  
                colleague.self();  
            }  
        }else { //与其他同事合作  
            if("ColleagueA".equals(name)) {  
                ColleagueA colleague = (ColleagueA)super.colleagues.get("ColleagueA");  
                colleague.out();  
            }else {  
                ColleagueB colleague = (ColleagueB)super.colleagues.get("ColleagueB");  
                colleague.out();  
            }  
        }  
    }  
} 
//测试类  
public class Client {  
    public static void main(String[] args) {  

        //创建一个中介者  
        AbstractMediator mediator = new Mediator();  

        //创建两个同事  
        ColleagueA colleagueA = new ColleagueA(mediator);  
        ColleagueB colleagueB = new ColleagueB(mediator);  

        //中介者分别与每个同事建立联系  
        mediator.addColleague("ColleagueA", colleagueA);  
        mediator.addColleague("ColleagueB", colleagueB);  

        //同事们开始工作  
        colleagueA.self();  
        colleagueA.out();  
        System.out.println("=======合作愉快,任务完成!\n");  

        colleagueB.self();  
        colleagueB.out();  
        System.out.println("=======合作愉快,任务完成!");  
    }  
} 

随着同时类的增多,Mediator会出现一段冗长的判断代码。虽然可以把它们分解并增加到Mediator类的私有方法中,但具体的业务逻辑还是少不了的。

但在平时项目中,硬是将各业务的类抽象出一个Colleague父类是不太合理的,因为子类之间的业务逻辑不同,导致他们很难抽象出一些共用方法。在这种情况下,可以省去Colleague这个角色,让Mediator直接依赖于几个同事子类。同事也不需要定义Mediator接口,把具体的中介者对象实现成为单例。 这样同时对象不再持有中介者,而是在需要的时候直接获取中介者对象并调用。中介者也不再持有同事对象,而是在具体处理方法里面去创建或者获取需要的同事对象。
不定义中介者接口,把具体中介者对象实现成为单例。同事对象不持有中介者,而是在需要的时矣直接获取中介者对象并调用。

4.代码实例

  • KeyguardViewMediator:
    KeyguardViewMediator是Android中整个待机解/锁屏业务的调度器,负责调度锁屏界面的相关动作及查询解锁屏状态。 KeyguardSercice(锁屏服务)通过KeyguardMediator(锁屏中介者)来协调各种Manager的状态以实现锁屏功能。

KeyguardSercice部分代码:

public class KeyguardService extends Service {
    //中介者角色
    private KeyguardViewMediator mKeyguardViewMediator;

    @Override
    public void onCreate() {
        ......
        //中介者角色初始化
        mKeyguardViewMediator =
                ((SystemUIApplication) getApplication()).getComponent(KeyguardViewMediator.class);
        .......
    }

    private final IKeyguardService.Stub mBinder = new IKeyguardService.Stub() {

        @Override // Binder interface
        public void addStateMonitorCallback(IKeyguardStateCallback callback) {
            ......
            //添加锁屏状态回调
            mKeyguardViewMediator.addStateMonitorCallback(callback);//调用中介者角色
            ......
        }

        @Override // Binder interface
        public void verifyUnlock(IKeyguardExitCallback callback) {
            ......
            //
            mKeyguardViewMediator.verifyUnlock(callback);//调用中介者角色
            ......
        }
        
        @Override
        public void onActivityDrawn() {
            ......
            mKeyguardViewMediator.onActivityDrawn();//调用中介者角色
            ......
        }
    };

}
  • FingerprintUnlockController(同事角色): FingerprintUnlockController就是 用于协调UI的所有指纹解锁操作的控制器
public class FingerprintUnlockController extends KeyguardUpdateMonitorCallback {
  //中介者角色
  private KeyguardViewMediator mKeyguardViewMediator;
    @Override
    public void onFingerprintAuthenticated(int userId) {
        ......       
        switch (mMode) {
            ...... 
            case MODE_WAKE_AND_UNLOCK:
                ...... 
                //调用角色者模式
                mKeyguardViewMediator.onWakeAndUnlocking();
                ...... 
    }
}

在这中KeyguardService和Android系统中的各种Mangaer都充当了同事的角色。

  • TutorMediator + Router :
    见项目代码

5.优缺点和适用场景

优点

  • 降低模块内部之间的类的相互引用,中介者模式使得对象之间不需要显示的相互引用,从而使得系统或模块内部相互解耦。
  • 减少子类的生成
  • 符合迪米特原则

缺点

  • 由于中介者对象封装了各个类之间的交互,会导致中介者类本身的复杂性上升,会有一定的维护成本

应用场景

  • 当对象之间存在复杂的网状结构关系而导致依赖关系混乱且难以复用时。
  • 当想创建一个运行于多个类之间的对象,又不想生成新的子类时。

6.与其他模式的区别

(1)观察者模式

中介者(mediator)强调的是同事(colleague)类之间的交互,通过中介者来避免组件之间的直接依赖
而观察者(observer)中的目标类(subject)强调是目标改变后对观察者进行统一的通讯,通过订阅-发布 模型,消除组件之间的双向依赖。

(2)代理模式

  • 代理者与被代理者之间可能是一对一对的关系。中介者模式则是多对多,中介者的功能多样,客户也可以为多个。
  • 代理模式通常是单向代理,例如B是C的代理,则A可以通过B访问C,但C不能通过B访问A
  • 中介者模式更加关注多个模块通信的解耦,代理模式更加关注于权限的封装。

(3)外观模式

  • 外观模式是结构型模式,中介者模式是行为型模式
  • 外观模式是对子系统提供的统一的接口,中介者模式是用一个中介来封装一系列同事对象的交互行为。
  • 外观模式中通信是单向的,中介者模式中通信是双向的
  • 外观模式所有的请求处理都委托给子系统完成,且子系统不需要知道外观类的存在,而中介者模式则由中心协调同事类和中心本身共同完成业务。

参考文章

blog.csdn.net/u012124438/…
blog.csdn.net/mengmei16/a…
www.jianshu.com/p/b07fb1e48…