Scott's world.

设计模式-中介者模式

Word count: 1.9kReading time: 7 min
2019/08/16 Share

设计模式-中介者模式

模式定义

中介者模式(Mediator Pattern)

  • 定义:用一个中介对象来封装一系列的对象交互,中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。中介者模式又称为调停者模式,它是一种对象行为型模式。

模式结构

中介者模式包含如下角色:

  • Mediator: 抽象中介者(定义好同事类对象到中介者对象的接口,用于各个同事类之间的通信。一般包括一个或几个抽象的事件方法,并由子类去实现。)

  • ConcreteMediator: 具体中介者(从抽象中介者继承而来,实现抽象中介者中定义的事件方法。从一个同事类接收消息,然后通过消息影响其他同时类。)

  • Colleague: 抽象同事类

  • ConcreteColleague: 具体同事类(如果一个对象会影响其他的对象,同时也会被其他对象影响,那么这两个对象称为同事类。在类图中,同事类只有一个,这其实是现实的省略,在实际应用中,同事类一般由多个组成,他们之间相互影响,相互依赖。同事类越多,关系越复杂。并且,同事类也可以表现为继承了同一个抽象类的一组实现组成。在中介者模式中,同事类之间必须通过中介者才能进行消息传递。)

模式分析

一般来说,同事类之间的关系是比较复杂的,多个同事类之间互相关联时,他们之间的关系会呈现为复杂的网状结构,这是一种过度耦合的架构,即不利于类的复用,也不稳定。

例如,现在我们来想象下面有六个同事类对象,每个对象之间都有不同的关系,意味着每个人对可以互相产生影响

如果我们使用中介者模式,我们可以从图中看到任何一个类的变动只会影响其类变身以及中介者,这样也就减小了系统的耦合程度

一个好的设计,必定不会把所有的对象关系处理逻辑封装在本类中,而是使用一个专门的类来管理那些不属于自己的行为。

代码实现

我们现在来设想一个例子

有两个类A和B,类中各有一个数字,并且要保证类B中的数字永远是类A中数字的100倍。也就是说,当修改类A的数时,将这个数字乘以1000赋给类B,而修改类B时,要将数除以1000赋给类A。类A类B互相影响,就称为同事类。代码如下:

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
abstract class AbstractColleague {
protected int number;
public int getNumber() {
return number;
}
public void setNumber(int number){
this.number = number;
}
//抽象方法,修改数字时同时修改关联对象
public abstract void setNumber(int number, AbstractColleague coll);
}

class ColleagueA extends AbstractColleague{
public void setNumber(int number, AbstractColleague coll) {
this.number = number;
coll.setNumber(number*1000);
}
}

class ColleagueB extends AbstractColleague{

public void setNumber(int number, AbstractColleague coll) {
this.number = number;
coll.setNumber(number/1000);
}
}

public class Client {
public static void main(String[] args){

AbstractColleague collA = new ColleagueA();
AbstractColleague collB = new ColleagueB();

System.out.println("设置A影响B");
collA.setNumber(1000, collB);
System.out.println("collA的number值:"+collA.getNumber());
System.out.println("collB的number值:"+collB.getNumber());

System.out.println("设置B影响A");
collB.setNumber(5000, collA);
System.out.println("collB的number值:"+collB.getNumber());
System.out.println("collA的number值:"+collA.getNumber());
}
}

上面的代码中,类A类B通过直接的关联发生关系,假如我们要使用中介者模式,类A类B之间则不可以直接关联,他们之间必须要通过一个中介者来达到关联的目的。

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
abstract class AbstractColleague {
protected int number;

public int getNumber() {
return number;
}

public void setNumber(int number){
this.number = number;
}
//注意这里的参数不再是同事类,而是一个中介者
public abstract void setNumber(int number, AbstractMediator am);
}

class ColleagueA extends AbstractColleague{

public void setNumber(int number, AbstractMediator am) {
this.number = number;
am.AaffectB();
}
}

class ColleagueB extends AbstractColleague{

@Override
public void setNumber(int number, AbstractMediator am) {
this.number = number;
am.BaffectA();
}
}

abstract class AbstractMediator {
protected AbstractColleague A;
protected AbstractColleague B;

public AbstractMediator(AbstractColleague a, AbstractColleague b) {
A = a;
B = b;
}

public abstract void AaffectB();

public abstract void BaffectA();

}
class Mediator extends AbstractMediator {

public Mediator(AbstractColleague a, AbstractColleague b) {
super(a, b);
}

//处理A对B的影响
public void AaffectB() {
int number = A.getNumber();
B.setNumber(number*1000);
}

//处理B对A的影响
public void BaffectA() {
int number = B.getNumber();
A.setNumber(number/1000);
}
}

public class Client {
public static void main(String[] args){
AbstractColleague collA = new ColleagueA();
AbstractColleague collB = new ColleagueB();

AbstractMediator am = new Mediator(collA, collB);

System.out.println("==========通过设置A影响B==========");
collA.setNumber(1000, am);
System.out.println("collA的number值为:"+collA.getNumber());
System.out.println("collB的number值为A的10倍:"+collB.getNumber());

System.out.println("==========通过设置B影响A==========");
collB.setNumber(1000, am);
System.out.println("collB的number值为:"+collB.getNumber());
System.out.println("collA的number值为B的0.1倍:"+collA.getNumber());

}
}

模式优缺点

  • 优点

    • 简化了对象之间的交互。
    • 将各同事解耦。
    • 减少子类生成。
    • 可以简化各同事类的设计和实现。
  • 缺点

    • 在具体中介者类中包含了同事之间的交互细节,可能会导致具体中介者类非常复杂,使得系统难以维护。

适用场景

  • 系统中对象之间存在复杂的引用关系,产生的相互依赖关系结构混乱且难以理解。
  • 一个对象由于引用了其他很多对象并且直接和这些对象通信,导致难以复用该对象。
  • 想通过一个中间类来封装多个类中的行为,而又不想生成太多的子类。可以通过引入中介者类来实现,在中介者中定义对象。
  • 交互的公共行为,如果需要改变行为则可以增加新的中介者类。

我们在MVC架构中控制器就可以看出,其实控制器控制着View模型和Model模型

模式拓展

中介者模式与迪米特法则

  • 在中介者模式中,通过创造出一个中介者对象,将系统中有关的对象所引用的其他对象数目减少到最少,使得一个对象与其同事之间的相互作用被这个对象与中介者对象之间的相互作用所取代。因此,中介者模式就是迪米特法则的一个典型应用。

中介者模式与GUI开发

  • 中介者模式可以方便地应用于图形界面(GUI)开发中,在比较复杂的界面中可能存在多个界面组件之间的交互关系。
  • 对于这些复杂的交互关系,有时候我们可以引入一个中介者类,将这些交互的组件作为具体的同事类,将它们之间的引用和控制关系交由中介者负责,在一定程度上简化系统的交互,这也是中介者模式的常见应用之一。

模式总结

中介者模式是一种比较常用的模式,也是一种比较容易被滥用的模式。对于大多数的情况,同事类之间的关系不会复杂到混乱不堪的网状结构,因此,大多数情况下,将对象间的依赖关系封装的同事类内部就可以的,没有必要非引入中介者模式。滥用中介者模式,只会让事情变的更复杂。

参考

https://blog.csdn.net/zhengzhb/column/info/pattern

https://blog.csdn.net/hguisu/article/details/7556625

https://design-patterns.readthedocs.io/zh_CN/latest/behavioral_patterns/observer.html

CATALOG
  1. 1. 设计模式-中介者模式
    1. 1.1. 模式定义
    2. 1.2. 模式结构
    3. 1.3. 模式分析
    4. 1.4. 代码实现
    5. 1.5. 模式优缺点
    6. 1.6. 适用场景
    7. 1.7. 模式拓展
    8. 1.8. 模式总结
    9. 1.9. 参考