中介者模式

1、天气预报项目需求

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

2)主人要看电视时,各个设备可以协同工作,自动完成看电视的准备工作,比如流程为:闹铃响起->咖啡机开始做咖啡->窗帘自动落下->电视机开始播放。

【普通解决方案】

闹钟类发送消息给咖啡机类,咖啡机类启动后通知窗帘类,窗帘类落下后通知TV类。

【方案问题分析】

1)当各电器对象有多种状态改变时,相互之间的调用关系会比较复杂。

2)各个电器对象彼此联系,你中有我,我中有你,不利于松耦合。

3)各个电器对象之间所传递的消息(参数),容易混乱。

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


2、中介者模式的基本介绍

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

2)中介者模式属于行为型模式,使代码易于维护。

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

【中介者模式的角色及职责】
  • 抽象中介者(Mediator)角色:定义了同事对象到中介者对象的接口,提供了同事对象注册与转发同事对象信息的抽象方法。
  • 具体中介者(ConcreteMediator)角色:实现中介者接口,实现抽象方法。他需要知道所有的具体的同事类,即以一个集合HashMap / List来管理,并接受某个同事对象消息,完成相应的任务。
  • 抽象同事类(Colleague)角色:定义同事类的接口,保存中介者对象,提供同事对象交互的抽象方法,实现所有相互影响的同事类的公共功能。
  • 具体的同事类(ConcreteColleague)角色:是抽象同事类的实现者,会有很多,每个同事只知道自己的行为,而不了解其他同事类的行为(方法),但是他们都依赖中介者对象。当需要与其他同事对象交互时,由中介者对象负责后续的交互。

3、应用实例代码实现

【智能家庭的操作流程】

1)创建ConcreMediator对象。

2)创建各个同事类对象,比如:Alarm、CoffeeMachine、TV…

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

4)同事类对象,可以调用sendMessage,最终会去调用ConcreteMediator的getMessage方法。

5)getMessage会根据接收到的同事对象发出的消息来协调调用其他的同事对象完成任务。

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

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
// 抽象中介者类
public abstract class Mediator {
// 将同事对象加入集合
public abstract void Register(String colleagueName, Colleague colleague);

// 接受消息,具体的同事对象发出
public abstract void GetMessage(int stateChange, String colleague);
public abstract void SendMessage();
}

// 具体的中介者类
public class ConcreteMediator extends Mediator {
private HashMap<String, Colleague> colleagueMap;
private HashMap<String, String> interMap;

public ConcreteMediator() {
colleague = new HashMap();
interMap = new HashMap();
}

@Override
public void Register(String colleagueName, Colleague colleague) {
colleagueMap.put(colleagueName, colleague);
if(colleague instanceof Alarm) {
interMap.put("Alarm", colleagueName);
} else if (colleague instanceof CoffeeMachine) {
interMap.put("CoffeeMachine", colleagueName);
} else if (colleague instanceof TV) {
interMap.put("TV", colleagueName);
} else if (colleague instanceof Curtains) {
interMap.put("Curtains", colleagueName);
}
}

// 中介者在这个方法,协调各个具体的同事对象,完成任务。
@Override
public void GetMessage(int stateChange, String colleagueName) {
if(colleagueMap.get(colleagueName) instanceof Alarm) {
if(stateChange == 0) {
((CoffeeMachine)(colleagueMap.get(interMap.get("CoffeeMachine")))).StartCoffee();
((TV)(colleagueMap.get(interMap.get("TV")))).StartTV();
} else if (stateChange == 1) {
((TV)(colleagueMap.get(interMap.get("TV")))).StopTV();
}
} else if (colleagueMap.get(colleagueName) instanceof CoffeeMachine) {

} else if (colleagueMap.get(colleagueName) instanceof TV) {

} else if (colleagueMap.get(colleagueName) instanceof Curtains) {

}
}
}

// Colleague
public abstract class Colleague {
private Mediator mediator;
public String name;

public Colleague(Mediator mediator, String name) {
this.mediator = mediator;
this.name = name;
}

public Mediator GetMediator() {
return this.mediator;
}

public abstract void sendMessage(int stateChange);
}

// 同事类
public class Alarm extends Colleague {
public Alarm(Mediator mediator, String name) {
// 在创建Alarm同事对象时,将自己放入到ConcreteMediator对象中
super(mediator, name);
mediator.Register(name, this);
}

public void SendAlarm(int stateChange) {
SendMessage(stateChange);
}

@Override
public void SendMessage(int stateChange) {
// 调用的中介者对象的getMessage
this.GetMediator().GetMessage(stateChange, this.name);
}
}

public class CoffeeMachine extends Colleague {
...

@Override
public void SendMessage(int stateChange) {
this.GetMediator().GetMessage(stateChange, this.name);
}

public void StartCoffee() {
System.out.println("It's time to startcoffee!");
}

public void FinishCoffee() {
System.out.println("After 5 minutes!");
System.out.println("Coffee is ok!");
SendMessage(0);
}
}

public class Curtains extends Colleague {
public Curtains(Mediator mediator, String name) {
super(mediator, name);
mediator.Register(name, this);
}

public void UpCurtains() {
System.out.println("I am holding Up Curtains");
}

@Override
public void SendMessage(int stateChange) {
this.GetMediator().GetMessage(stateChange, this.name);
}
}

public class TV extends Colleague {
public TV(Mediator mediator, String name) {
super(mediator, name);
mediator.Register(name, this);
}

@Override
public void SendMessage(int stateChange) {
this.GetMediator().GetMessage(stateChange, this.name);
}

public void StartTv() {
System.out.println("It's time to StartTv!");
}

public void StopTv() {
System.out.println("It's time to StopTv!");
}
}

public class Client {
public static void main(String[] args) {
// 创建一个中介者
Mediator mediator = new ConcreteMediator();
Alarm alarm = new Alarm(mediator, "alarm");
CoffeeMachine coffeeMachine = new CoffeeMachine(mediator, "coffeeMachine");
Curtains curtains = new Curtains(mediator, "curtains");

TV tv = new TV(mediator, "TV");
alarm.SendAlarm(0);
coffeeMachine.FinishCoffee();
alarm.SendAlarm(1);
}
}

4、中介者模式的注意事项

1)多个类相互耦合,会形成网状结构,使用中介者模式将网状结构分离为星型结构,进行解耦。

2)减少类间依赖,降低了耦合,符合迪米特原则。

3)没有使用中介者模式的时候,同事对象之间的关系通常是一对多的,引入中介者对象以后,中介者对象和同事对象的关系通常变成双向的一对一,这回让对象的关系更容易理解和实现。

3)中介者承担了较多的责任,一旦中介者出现了问题,整个系统就会受到影响。

4)如果设计不当,中介者对象本身变得过于复杂,这点在实际使用时,要特别注意。

5)使用场景:系统中对象之间存在复杂的引用关系,系统结构混乱且难以理解。当想创建一个运行于多个类之间的对象,又不想生成新的子类时。