中介者模式原理及示例分析
设计模式系列总览
设计模式 | 飞机票 |
---|---|
三大工厂模式 | 登机入口 |
策略模式 | 登机入口 |
委派模式 | 登机入口 |
模板方法模式 | 登机入口 |
观察者模式 | 登机入口 |
单例模式 | 登机入口 |
原型模式 | 登机入口 |
代理模式 | 登机入口 |
装饰者模式 | 登机入口 |
适配器模式 | 登机入口 |
建造者模式 | 登机入口 |
责任链模式 | 登机入口 |
享元模式 | 登机入口 |
组合模式 | 登机入口 |
门面模式 | 登机入口 |
桥接模式 | 登机入口 |
中介者模式 | 登机入口 |
迭代器模式 | 登机入口 |
状态模式 | 登机入口 |
解释器模式 | 登机入口 |
备忘录模式 | 登机入口 |
命令模式 | 登机入口 |
访问者模式 | 登机入口 |
软件设计7大原则和设计模式总结 | 登机入口 |
前言
本文主要介绍中介者模式的原理,并会结合示例进行分析。中介者模式其实和桥接有点相似,桥接模式也是通过组合来实现的,但是中介者模式和桥接模式的侧重点不一样,接下来就让我们一起来看看中介者模式吧。
什么是中介者模式
中介者模式(Mediator Pattern)又称为调节者模式或者调停者模式,是用来降低多个对象和类之间的通信复杂性。
中介者模式中用一个中介对象封装一系列的对象交互,从而使各个对象不需要显示的相互作用,达到松耦合的目的,使得维护更加容易。当某些对象之间的作用发生改变时,不会立刻影响其他的一些对象之间的作用,保证了对象之间的相互作用可以独立的变化。
中介者模式属于行为型模式,其核心思想是通过中介者对象解耦各层次对象的直接耦合,层次对象的对外依赖通信全部交由中介者转发。
为什么需要中介者模式
假如现在有六个对象,对象与对象之间都需要互相调用,那么它们的关系就会如下图所示:
各个对象之间互相依赖,整个依赖关系形成了网状,关系错综复杂,非常难以管理。这时候如果引入一个中介者,每个对象都只和中介者交互,那么它们之间的关系就会如下图所示:
可以看到,所有的对象之间的关系都归中介者进行统一管理,避免了各个对象之间各自依赖的乱像。
其实在生活中也一样,比如飞机航线,假如有多驾飞机都需要走同一条航线,那么到底什么时候能走,谁先走就会是一个问题,如果各架飞机之间自己去协商,那么会非常复杂而且容易出错,所以这时候就需要有塔台来统一调度,而塔台扮演的角色就是中介者对象。
中介者模式示例
好了,装逼时刻又到了:Talk is cheap,Show you the code,先看一个非常简单的例子。
我们就以上面的航空塔台为例子来写一个示例:
1、首先建立一个抽象的 Plane
类,当然这里其实可以不用抽象类,为了方便功能扩展一般我们都是建议面向抽象编程:
package com.lonely.wolf.note.design.pattern.mediator;
public abstract class AbstractPlane {
protected AbstractMediator mediator;
public AbstractPlane(AbstractMediator mediator) {
this.mediator = mediator;
}
public abstract void fly();
}
注意这里面持有了一个抽象中介者对象的引用,稍后我们就会建立中介者对象
2、然后新建两个具体的 PlaneA
和 PlaneB
来继承抽象服务类:
package com.lonely.wolf.note.design.pattern.mediator;
public class PlaneA extends AbstractPlane {
public PlaneA(AbstractMediator mediator) {
super(mediator);
}
@Override
public void fly() {
System.out.println("我是PlaneA,要过航线,请让道");
super.mediator.notifyPlaneB();
}
public void notifyMe(){
System.out.println("我是PlaneA,已收到通知,准备让道");
}
}
package com.lonely.wolf.note.design.pattern.mediator;
public class PlaneB extends AbstractPlane {
public PlaneB(AbstractMediator mediator) {
super(mediator);
}
@Override
public void fly() {
System.out.println("我是PlaneB,要过航线,请让道");
super.mediator.notifyPlaneA();
}
public void notifyMe(){
System.out.println("我是PlaneB,已收到通知,准备让道");
}
}
注意上面这两个类,重写的抽象方法 fly()
会依赖另一个服务,另外各自有一个接收对方服务的方法 notifyMe()
,如果说我们不使用中介者对象来实现,那么 A
就必须要持有 B
,而 B
又要持有 A
,服务一多,调用关系就会呈现上面的网状形式。而如果有了中介者对象就不一样了,这些服务就可以全部交由中介者来统一管理。
3、建立一个抽象中介者对象:
package com.lonely.wolf.note.design.pattern.mediator;
public abstract class AbstractMediator {
protected PlaneA planeA;
protected PlaneB planeB;
public void setPlaneA(PlaneA planeA) {
this.planeA = planeA;
}
public void setPlaneB(PlaneB planeB) {
this.planeB = planeB;
}
public abstract void notifyPlaneA();
public abstract void notifyPlaneB();
}
4、再建立一个具体的中介者对象塔台:
package com.lonely.wolf.note.design.pattern.mediator;
public class ControlTower extends AbstractMediator{
@Override
public void notifyPlaneA() {
super.planeA.notifyMe();
}
@Override
public void notifyPlaneB() {
super.planeB.notifyMe();
}
}
5、最后我们建立一个测试类来测试一下:
package com.lonely.wolf.note.design.pattern.mediator;
public class TestMediator {
public static void main(String[] args) {
AbstractMediator controlTower = new ControlTower();
PlaneA planeA = new PlaneA(controlTower);
PlaneB planeB = new PlaneB(controlTower);
controlTower.setPlaneA(planeA);
controlTower.setPlaneB(planeB);
planeA.fly();
System.out.println("--------------------");
planeB.fly();
}
}
输出结果如下:
我是PlaneA,要过航线,请让道
我是PlaneB,已收到通知,准备让道
--------------------
我是PlaneB,要过航线,请让道
我是PlaneA,已收到通知,准备让道
可以看到,在这个例子中我们实现了 PlaneA
和 PlaneB
的互相调用,但是相互都不持有对方的引用,而是通过一个中介者对象来统一管理,如果后续需要新增其他服务的调用,那么只需要改变中介者对象就可以了。
中介者模式角色
从上面示例中,我们可以得出中介者模式主要有4个角色:
- 抽象中介者(Mediator):定义一个抽象角色,用于各个同事角色之间的通信(如示例中的AbstractMediator)。
- 具体中介者(ConcreteMediator):从具体同事的对象接收消息,并像具体同事对象发出命令,用来协调各个同事对象之间通信协作(如示例中的
ControlTower
)。 - 抽象同事类(Colleague):每一个同事对象均需要依赖中介者角色,所以一般将中介者角色集成到该角色之中,与其他同事在通信时,通过中介者角色进行转发(如示例中的
AbstractPlane
)。 - 具体同事类(ConcreteColleague):负责实现自发行为(Self-Method),转发依赖方法(Dep-Method)交由中介者进行协调处理(如示例中的
PlaneA
和PlaneB
,自发行为就是方法notifyMe()
方法,转发行为对应fly()
方法)。
中介者模式和桥接模式的区别
上一篇我们分析了桥接模式,看起来和这里的中介者模式有点相似的感觉。其实这两种设计模式的思想是一样的,这两种模式的侧重点和应用场景不一致。
桥接模式侧重的是将抽象和具体进行解耦,也就是一般就是特指2个维度,一个抽象,一个具体,比如桥接模式示例中的消息类型(邮箱消息,SMS消息)这就是抽象维度,而消息的紧急程度(如普通消息,紧急消息)这就是具体维度,然后将这两个维度通过一个中间对象(抽象角色)进行关联。
中介者模式侧重的是将多个相同类型对象之间的关联关系进行统一管理。
中介者模式在JDK源码中应用
我们打开JDK源码中的Timer类。我们任意查看其中的几个schedule方法:
可以看到都调用了sched方法,那么我们再来看看sched方法:
可以看到,所有的task都放入了Timer类中维护的task队列中。所以Timer就是充当了一个中介者的角色,而task队列内的任务就是具体同事对象。
中介者模式应用场景
中介者模式在我们日常生活中非常常见,比如租房中介,买房中介等,还有像我们的群聊,聊天室等等都有中介者的身影。中介者模式主要适用于以下场景:
- 1、系统中的对象存在非常复杂的引用关系,而且相互依赖,导致依赖关系非常复杂时。
- 2、当我们想要使用多个类之间的行为时,为了避免过多的使用继承,可以考虑使用中介者来实现。
中介者模式优缺点
优点:
- 1、减少了类之间的相互依赖性,将多对多依赖转化成为了一对多依赖,降低了类间的耦合。
- 2、使用了中介者模式之后,各个类都各司其职,符合了迪米特法则。
缺点
- 1、当我们的同事角色非常多的时候,中介者对象需要维护非常多的同事角色对象,会使得中介者变得非常庞大,导致难以维护。
总结
本文主要介绍了中介者模式的定义并解释了为什么我们需要一个中介者,并通过一个简单的示例来帮助更好的理解中介者模式的思想,最后介绍了中介者模式在JDK源码中的体现。
请关注我,和孤狼一起学习进步。