设计模式(23):中介者模式MEDIATOR

中介者模式

意图

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


使用场景

在下列情况下使用中介者模式:

  • 一组对象以定义良好但是复杂的方式进行通信。产生的相互依赖关系结构混乱且难以理解。
  • 一个对象引用其他很多对象并且直接与这些对象通信,导致难以复用该对象。
  • 想定制一个分布在多个类中的行为,而又不想生成太多的子类。

结构

中介者模式结构如下
ShowImage

  • Mediator

    – 中介者定义一个接口用于与各同事(Colleague)对象通信。

  • ConcreteMediator

    – 具体中介者通过协调各同事对象实现协作行为。

    – 了解并维护它的各个同事。

  • Colleague

    – 每一个同事类都知道它的中介者对象。

    – 每一个同事对象在需与其他的同事通信的时候,与它的中介者通信。

协作

Colleague向一个Mediator对象发送和接收请求。Mediator在各Coleague间适当地转发请求以实现协作行为。


效果

中介者模式有以下优点和缺点:

  1. 减少了子类生成

    Mediator将原本分布于多个对象间的行为集中在一起。改变这些行为只需生成Mediator的子类即可。这样各个Colleague类可被重用。

  2. 它将各Colleague解耦

    Mediator有利于各Colleague间的松耦合. 你可以独立的改变和复用各Colleague类和Mediator类。

  3. 它简化了对象协议

    用Mediator和各Colleague间的一对多的交互来代替多对多的交互。一对多的关系更易于理解、维护和扩展。

  4. 它对对象如何协作进行了抽象

    将中介作为一个独立的概念并将其封装在一个对象中,使你将注意力从对象各自本身的行为转移到它们之间的交互上来。这有助于弄清楚一个系统中的对象是如何交互的。

  5. 它使控制集中化

    中介者模式将交互的复杂性变为中介者的复杂性。因为中介者封装
    了协议, 它可能变得比任一个Colleague都复杂。这可能使得中介者自身成为一个难于维护的
    庞然大物。

中介者模式实现(Implement)

案例

机场的空管控制塔在调度降落的飞机任务中扮演着至关重要的角色。
假如没有空管控制塔,那么调度任务是极度艰难的,航班之间需要互相通信
ShowImage

但是有了空管控制塔,调度就变得方便许多了,所有航班只需要与空管控制塔通信即可,这里的空管控制塔就相当于中介者(Mediator)。
ShowImage

代码实现

客机,模式中的Colleague

1
2
3
4
5
6
7
8
9
/* 客机, Colleague in Pattern */
public abstract class AirlinerColleague {
/* 与空管控制塔取得联系, 准备降落 */
public abstract void prepareLanding(ATMTower atmTower);
/* 空管塔已经调度完成, 即将降落 */
public abstract void land();
}

空管调度塔,模式中的Mediator

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/* ATM means Air Traffic Management 空管
* ATMTower 空管控制塔, Mediator in Pattern */
public abstract class ATMTower {
private String airportName;
protected List<AirlinerColleague> airlinerList = new ArrayList<>();
public abstract void addLandingAirliner(AirlinerColleague airlinerColleague);
public abstract void scheduleLandingAirliners();
public String getAirportName() {
return airportName;
}
protected void setAirportName(String airportName) {
this.airportName = airportName;
}
}

双流机场空管控制塔,模式中的ConcreteColleague

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/* 双流机场空管控制塔
* ConcreteMediator in Pattern */
public class ShuangliuATMTower extends ATMTower {
public ShuangliuATMTower() {
this.setAirportName("双流机场");
}
@Override
public void addLandingAirliner(AirlinerColleague airlinerColleague) {
airlinerList.add(airlinerColleague);
}
@Override
public void scheduleLandingAirliners() {
for (AirlinerColleague airlinerColleague : airlinerList) {
airlinerColleague.land();
}
}
}

这里只列出一个航班,其他的省略

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/* AB0001号航班, ConcreteColleague in Pattern*/
public class AirlinerAB0001 extends AirlinerColleague {
@Override
public void prepareLanding(ATMTower atmTower) {
atmTower.addLandingAirliner(this);
System.out.println("AB0001号航班即将抵达" + atmTower.getAirportName());
}
@Override
public void land() {
System.out.println("AB0001号航班降落机场...");
}
}

举例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class MediatorDemoTest {
@Test
public void shuangliuAirportTest() {
//实例化ConcreteMediator
ATMTower atmTower = new ShuangliuATMTower();
//机场同时来了四架客机
AirlinerColleague airliner1 = new AirlinerAB0001();
AirlinerColleague airliner2 = new AirlinerCD0002();
AirlinerColleague airliner3 = new AirlinerEF0003();
AirlinerColleague airliner4 = new AirlinerGH0004();
System.out.println("-----双流机场同时来了四架客机-----");
//准备降落
airliner1.prepareLanding(atmTower);
airliner3.prepareLanding(atmTower);
airliner4.prepareLanding(atmTower);
airliner2.prepareLanding(atmTower);
System.out.println("-----四架客机准备降落-----");
//空管控制塔进行调度
System.out.println("空管控制台对即将降落的航班进行调度...");
atmTower.scheduleLandingAirliners();
}
}

运行结果

1
2
3
4
5
6
7
8
9
10
11
-----双流机场同时来了四架客机-----
AB0001号航班即将抵达双流机场
EF0003号航班即将抵达双流机场
GH0004号航班即将抵达双流机场
CD0002号航班即将抵达双流机场
-----四架客机准备降落-----
空管控制台对即将降落的航班进行调度...
AB0001号航班降落机场...
EF0003号航班降落机场...
GH0004号航班降落机场...
CD0002号航班降落机场...

总结

中介者模式通过提供一个中介类来处理类与类之间的通信,使得类之间关系解耦。但是过度依赖中介者会使得中介者代码变得膨胀,中介者变得复杂难以维护。

参考代码

------ 本文结束 ------

版权声明


BillyYccc's blog by Billy Yuan is licensed under a Creative Commons BY-NC-SA 4.0 International License.
本文原创于BillyYccc's Blog,转载请注明原作者及出处!