这篇博客我们介绍一下中介者模式(Mediator Pattern),也是行为型模式之一,中介者模式也称为调解者模式或者调停者模式,顾名思义,它的作用是在若干类或者若干模块之间承当中介。
通常情况下,一个程序必然要包含大量的类,随着项目的进行,类和模块的数量必然要进一步增加,特别是当需要维护或者重构时,类与类之间复杂的网状结构会让事情变得越来越复杂,降低程序的可读性和可维护性,并且修改一个类需要牵涉到其他类,不符合开闭原则。所以此时中介者模式能够将这些网状结构的类变成星型依赖,所以类都只依赖于中介者,不直接依赖于其他类。
转载请注明出处:http://blog.csdn.net/self_study/article/details/52344610。
PS:对技术感兴趣的同鞋加群544645972一起交流。
设计模式总目录
特点
中介者模式包装了一系列对象相互作用的方式,使得这些对象不必相互明显作用,从而使耦合松散,而且可以独立地改变它们之间的交互。
中介者模式可以将多对多的网状结构转换成一对多的星型结构,达到降低系统的复杂性,提高可扩展性的作用。在没有中介者角色之前,所有对象都需要依赖其他对象,持有他们的引用,也就是说对象之间是紧耦合的,有了中介者之后,一切就简单了,每个对象都会在自己状态改变时,告诉中介者,每个对象都会对中介者发出的请求做出回应。
所以中介者模式适合的场景就很明确了:当对象之间的交互操作很多且每个对象的行为操作都依赖彼此时,为防止在修改一个对象的行为时,同时涉及修改很多其他对象的行为,可采用中介者模式,来解决紧耦合的问题。
UML类图
我们来看看中介者模式的 uml 类图:
中介者模式有三个角色:
- Mediator:抽象中介者角色,定义了同事对象到中介者对象的接口,可以通过抽象类或者接口的方式实现;
- ConcreteMediator:具体中介者角色,继承或者实现了抽象中介者,实现了父类定义的方法,它从具体的同事对象接受消息,向具体同事对象发出命令;
- Colleague:抽象同事类角色,定义了同事对象的接口,它只知道中介者而不知道其他的同事对象;
- ConcreteColleague:具体同事类角色,继承抽象同事类,每个具体同事类都知道本身在小范围内的行为,而不知道它在大范围内的目的。
抽象同事类:
Colleague.class
public abstract class Colleague {
protected Mediator mediator;
public void setMediator(Mediator mediator) {
this.mediator = mediator;
}
public abstract void operation();
}
具体同事类:
ConcreteColleagueA.class && ConcreteColleagueB.class
public class ConcreteColleagueA extends Colleague{
public void notifyColleagueB() {
mediator.notifyColleagueB();
}
@Override
public void operation() {
System.out.print("this is ConcreteColleagueA's operation\n");
}
}
public class ConcreteColleagueB extends Colleague{
public void notifyColleagueA() {
mediator.notifyColleagueA();
}
@Override
public void operation() {
System.out.print("this is ConcreteColleagueB's operation\n");
}
}
抽象中介者角色:
Mediator.class
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();
}
ConcreteMediator.class
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();
}
}
最后结果:
this is ConcreteColleagueB's operation
this is ConcreteColleagueA's operation
两个 Colleague 类成功通过 Mediator 进行了相互作用。上面这个是中介者模式的标准写法,就我自己在项目中实际使用中介者模式来说,有时候将同事子类抽象出一个 Colleague 父类是不太合理的,因为子类之间的业务逻辑的不同,导致他们很难抽象出一些公用方法,所以这时候使用中介者模式,可以省去 Colleague 这个角色,让 Mediator 直接依赖于几个同事子类;同时也可以不定义Mediator接口,把具体的中介者对象实现成为单例,这样同事对象不再持有中介者,而是在需要的时候直接获取中介者对象并调用;中介者也不再持有同事对象,而是在具体处理方法里面去创建,或获取,或从数据传入需要的同事对象。
示例与源码
在 Android 源码中也有很多使用中介者模式的例子,比如最突出的就是 Binder 中的 Binder Driver 这个角色,它连接了 Binder client , Binder server 和 ServiceManager,相当于一个中介者,感兴趣的可以去看看我的这篇博客android IPC通信(下)-AIDL。
我这里仍然以 wiki 的 demo 为例,使用 Mediator 来控制 3 个按钮实现 book,view 和 search 的功能:
同事类角色:
Command.class
interface Command {
void execute();
}
BtnView.class、BtnSearch.class、BtnBook.class、LblDisplay.class
class BtnView extends JButton implements Command {
Mediator med;
BtnView(ActionListener al, Mediator m) {
super("View");
addActionListener(al);
med = m;
med.registerView(this);
}
public void execute() {
med.view();
}
}
class BtnSearch extends JButton implements Command {
Mediator med;
BtnSearch(ActionListener al, Mediator m) {
super("Search");
addActionListener(al);
med = m;
med.registerSearch(this);
}
public void execute() {
med.search();
}
}
class BtnBook extends JButton implements Command {
Mediator med;
BtnBook(ActionListener al, Mediator m) {
super("Book");
addActionListener(al);
med = m;
med.registerBook(this);
}
public void execute() {
med.book();
}
}
class LblDisplay extends JLabel {
Mediator med;
LblDisplay(Mediator m) {
super("Just start...");
med = m;
med.registerDisplay(this);
setFont(new Font("Arial", Font.BOLD, 24));
}
}
中介者角色:
Mediator.class
interface Mediator {
void book();
void view();
void search();
void registerView(BtnView v);
void registerSearch(BtnSearch s);
void registerBook(BtnBook b);
void registerDisplay(LblDisplay d);
}
ParticipantMediator.class
class ParticipantMediator implements Mediator {
BtnView btnView;
BtnSearch btnSearch;
BtnBook btnBook;
LblDisplay show;
//....
public void registerView(BtnView v) {
btnView = v;
}
public void registerSearch(BtnSearch s) {
btnSearch = s;
}
public void registerBook(BtnBook b) {
btnBook = b;
}
public void registerDisplay(LblDisplay d) {
show = d;
}
public void book() {
btnBook.setEnabled(false);
btnView.setEnabled(true);
btnSearch.setEnabled(true);
show.setText("booking...");
}
public void view() {
btnView.setEnabled(false);
btnSearch.setEnabled(true);
btnBook.setEnabled(true);
show.setText("viewing...");
}
public void search() {
btnSearch.setEnabled(false);
btnView.setEnabled(true);
btnBook.setEnabled(true);
show.setText("searching...");
}
}
最后测试程序:
class MediatorDemo extends JFrame implements ActionListener {
Mediator med = new ParticipantMediator();
MediatorDemo() {
JPanel p = new JPanel();
p.add(new BtnView(this, med));
p.add(new BtnBook(this, med));
p.add(new BtnSearch(this, med));
getContentPane().add(new LblDisplay(med), "North");
getContentPane().add(p, "South");
setSize(400, 200);
setVisible(true);
}
public void actionPerformed(ActionEvent ae) {
Command comd = (Command) ae.getSource();
comd.execute();
}
public static void main(String[] args) {
new MediatorDemo();
}
}
用法可能和上面的有些差距,但是思想是一样的,代码也一目了然。
总结
在面向对象的变成语言里,一个类必然会与其他类产生依赖关系,如果这种依赖关系如网状般错综复杂,那么必然会影响我们的代码逻辑以及执行效率,适当地使用中介者模式可以对这种依赖关系进行解耦使逻辑结构清晰,但是,如果几个类之间的关系并不复杂,耦合也很少,使用中介者模式反而会使得原本不复杂的逻辑结构变得复杂,所以,我们在决定使用中介者模式之前需要多多考虑,权衡利弊。
优点:
- 适当的使用中介者模式可以避免同事类之间的过度耦合,使得各同事类之间可以相对独立地使用;
- 使用中介者模式可以将对象间一对多的关联转变为一对一的关联,使对象间的关系易于理解和维护;
- 使用中介者模式可以将对象的行为和协作进行抽象,能够比较灵活的处理对象间的相互作用。
- 使用中介者模式需要权衡一下,不能因为同事类少就不适合使用中介者模式,也不能因为同事类多就一定要使用中介者模式,重要的是解耦合,就算是三个类,他们直接的耦合很严密,导致一个类的修改会严重影响到另外两个类,这时候就可以考虑使用中介者,另一方面,类如果很多但是相互都是简单的连接,耦合性低,使用中介者模式就显得不是那么必要了;
- 随着同事子类的增多和类之间关系的复杂化,中介者会变得越来越庞大,减少可维护性。
源码下载
https://github.com/zhaozepeng/Design-Patterns/tree/master/MediatorPattern
引用
https://en.wikipedia.org/wiki/Mediator_pattern
http://blog.csdn.net/jason0539/article/details/45216585