中介者模式(Mediator Pattern) – 设计模式之行为型模式:
目录
消息中间类实现(通用中介者):MessageMediatorImpl
中介者模式(Mediator Pattern)
定义: Define an object that encapsulates how a set of objects interact. Mediator promotes loose coupling by keeping objects from referring to each other explicitly, and it lets you vary their interation independently.
用一个中介对象来封装一系列的对象交互。中介者使各对象不需要显示地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。
类图
中介者模式通用类图:
例子:
过程:
在海贼王中,海贼之间通过电话虫通信。比如红发提醒路飞,黑胡子有所行动,将要袭击他们。
代码:
海贼团:PirateCrews
public class PirateCrews {
private String name; // 名称
private PirateCrews pirateCrews; // 另外一个海贼团
public String getName() {
return this.name;
}
public PirateCrews(String name) {
this.name = name;
}
public void talk(PirateCrews pirateCrews, String msg) {
this.pirateCrews = pirateCrews; // 连接红发海贼团
System.out.println( "呼叫 " + pirateCrews.getName() + " " + msg);
}
}
测试:
public class PirateCrewTest {
public static void main(String[] arg) {
PirateCrews strawHat = new PirateCrews("红发海贼团");
PirateCrews redHaired = new PirateCrews("草帽海贼团");
redHaired.talk(strawHat, "告诉你们的船长,黑胡子海贼团将要攻打你们");
strawHat.talk(redHaired, "谢谢提醒,我们会做好准备的!");
}
}
结果:
呼叫 红发海贼团 告诉你们的船长,黑胡子海贼团将要攻打你们
呼叫 草帽海贼团 谢谢提醒,我们会做好准备的!
如果各个海贼团之间通信,就会显得很繁杂。需要用一个中介平台来处理。
优化:
过程:
在海贼王中海贼团通信通过电话虫,比如四皇之间的通信:
这样略显杂乱,他们之间交流使用一个中介消息通信,只要和消息中介发消息,中介进行转发消息。可以通知所有人,也可以单独通信
类图:
代码:
海贼团(抽象同事类):PirateCrew
/**
* 抽象同事类, 定义各同事的公有方法:
*/
public abstract class PirateCrew {
protected MessageMediator mediator;
private String name;
public PirateCrew(MessageMediator mediator, String name) {
this.mediator = mediator;
this.name = name;
}
public String getName() {
return name;
}
protected abstract void declareAll(String msg);
protected abstract void declare(PirateCrew toPirateCrew, String msg);
protected abstract void receive(String msg);
}
消息中间类(抽象中介者):MessageMediator
public abstract class MessageMediator {
protected List<PirateCrew> pirateCrews = new LinkedList<>();
public void register(PirateCrew pirateCrew) {
pirateCrews.add(pirateCrew);
}
public void remove(PirateCrew pirateCrew) {
pirateCrews.remove(pirateCrew);
}
protected abstract void declareAll(PirateCrew pirateCrew, String msg);
protected abstract void declare(PirateCrew fromPirateCrew, String msg, PirateCrew toPirateCrew);
}
在Mediator抽象类中我们只定义了同事类的注入,为什么使用注入抽象类,而不是使用同事实现类注入?每个同事类都有相同的方法,比如execute、handler等,那当然注入抽象类,做到依赖倒置。当每个同事类必须要完成的不同业务方法,使用同事实现类注入
消息中间类实现(通用中介者):MessageMediatorImpl
/**
* 了解并维护它的各个同事;
* 通过协调各同事对象实现协作行为(从同事接收消息, 向具体同事发出命令).
* 具体的中介者一般只有一个,即通用中介者
*/
public class MessageMediatorImpl extends MessageMediator {
// 循环所有海贼,只发消息给非发送方。
@Override
protected void declareAll(PirateCrew fromPirateCrew, String msg) {
ListUtils.emptyIfNull(pirateCrews).stream()
.filter(e -> !e.equals(fromPirateCrew)) // 过滤掉发送方
.forEach(to -> to.receive(fromPirateCrew.getName() +"声明:" +msg));
}
@Override
protected void declare(PirateCrew fromPirateCrew, String msg, PirateCrew toPirateCrew) {
toPirateCrew.receive(fromPirateCrew.getName()+" 发来消息说: "+msg);
}
}
黑胡子海贼团(具体同事类):Blackbeard
/**
* 每一个同事类都知道它的中介者对象.
* 每一个同事对象在需与其他同事通信时, 与它的中介者通信.
*/
public class Blackbeard extends PirateCrew {
public Blackbeard(MessageMediator mediator, String name) {
super(mediator, name);
}
@Override
protected void declareAll(String msg) {
mediator.declareAll(this, msg);
}
@Override
protected void declare(PirateCrew toPirateCrew, String msg) {
mediator.declare(this, msg, toPirateCrew);
}
@Override
protected void receive(String msg) {
System.out.println("黑胡子海贼团接收到: [" + msg + "]");
}
}
红发海贼团(具体同事类): RedHaired
/**
* 每一个同事类都知道它的中介者对象.
* 每一个同事对象在需与其他同事通信时, 与它的中介者通信.
*/
public class RedHaired extends PirateCrew {
public RedHaired(MessageMediator mediator, String name) {
super(mediator, name);
}
@Override
protected void declareAll(String msg) {
mediator.declareAll(this, msg);
}
@Override
protected void declare(PirateCrew toPirateCrew, String msg) {
mediator.declare(this, msg, toPirateCrew);
}
@Override
protected void receive(String msg) {
System.out.println("红发海贼团接收到: [" + msg + "]");
}
}
草帽海贼团(具体同事类): StrawHat
/**
* 每一个同事类都知道它的中介者对象.
* 每一个同事对象在需与其他同事通信时, 与它的中介者通信.
*/
public class StrawHat extends PirateCrew {
public StrawHat(MessageMediator mediator, String name) {
super(mediator, name);
}
@Override
protected void declareAll(String msg) {
mediator.declareAll(this, msg);
}
@Override
protected void declare(PirateCrew toPirateCrew, String msg) {
mediator.declare(this, msg, toPirateCrew);
}
@Override
protected void receive(String msg) {
System.out.println("草帽海贼团接收到: [" + msg + "]");
}
}
为什么同事类要使用构造函数注入中介者,而中介者使用getter/setter方式注入同事类呢?这是因为同事类必须有中介者,而中介者却可以只有部分同事类
测试:
public class PirateCrewTest {
public static void main(String[] args) {
MessageMediator mediator = new MessageMediatorImpl();
PirateCrew blackbeard = new Blackbeard(mediator, "黑胡子海贼团");
PirateCrew redHaired = new RedHaired(mediator, "红发海贼王");
PirateCrew strawHat = new StrawHat(mediator, "草帽海贼团");
mediator.register(blackbeard);
mediator.register(redHaired);
mediator.register(strawHat);
strawHat.declareAll("我们的船长路飞要成为海贼王!!!");
System.out.println("========================");
blackbeard.declareAll("我要灭了草帽海贼团,灭了红发海贼团,成为海贼王!!!");
System.out.println("========================");
redHaired.declareAll("大家和平相处,相互伤害对大家都没有好处");
System.out.println("========================");
strawHat.declare(redHaired,"香克斯大哥,黑胡子要来灭草帽海贼团,请帮助我们!");
System.out.println("========================");
redHaired.declare(strawHat,"我们一起联合起来搞黑胡子!");
}
}
结果:
黑胡子海贼团接收到: [草帽海贼团声明:我们的船长路飞要成为海贼王!!!]
红发海贼团接收到: [草帽海贼团声明:我们的船长路飞要成为海贼王!!!]
========================
红发海贼团接收到: [黑胡子海贼团声明:我要灭了草帽海贼团,灭了红发海贼团,成为海贼王!!!]
草帽海贼团接收到: [黑胡子海贼团声明:我要灭了草帽海贼团,灭了红发海贼团,成为海贼王!!!]
========================
黑胡子海贼团接收到: [红发海贼王声明:大家和平相处,相互伤害对大家都没有好处]
草帽海贼团接收到: [红发海贼王声明:大家和平相处,相互伤害对大家都没有好处]
========================
红发海贼团接收到: [草帽海贼团 发来消息说: 香克斯大哥,黑胡子要来灭草帽海贼团,请帮助我们!]
========================
草帽海贼团接收到: [红发海贼王 发来消息说: 我们一起联合起来搞黑胡子!]
总结:
在学习的时候,里面的通知所有,就想到了观察者模式里面的notifyAll这个方法。中介者模式的重点是在对象Colleague之间的通信封装到一个类中单独处理。 只要耦合中间类,而不用耦合其它要通信的类。
优点:
1、降低了类的复杂度,将一对多转化成了一对一。
2、各个类之间的解耦。
3、符合迪米特原则。
缺点: 中介者会庞大,变得复杂难以维护。
使用场景
中介者模式一般应用于一组对象以定义良好但是复杂的方式进行通信,比如得到的窗体Form或Web页面aspx,以及想定制一个分布在多个类中的行为,而又不想生成太多子类的场合。
中介者模式适用于多个对象之间紧密耦合的情况,紧密耦合的标准是:在类图中出现了蜘蛛网状结构。在这种情况下一定要考虑使用中介者模式,这有利于把蜘蛛网梳理为星型结构,使原本复杂混乱的关系变得清晰简单。
1, 机场调度中心
2, MVC框架
大家都应该使用过Struts,MVC框架,其中的C(Controller)就是一个中介者,叫做前端控制器(Front Controller),它的作用就是把M(Model,业务逻辑)和V(View,视图)隔离开,协调M和V协同工作,把M运行的结果和V代表的视图融合成一个前端可以展示的页面,减少M和V的依赖关系。MVC框架已经成为一个非常流行、成熟的开发框架,这也是中介者模式的优点的一个体现。
3, 媒体网关
媒体网关也是一个典型的中介者模式,比如使用MSN时,张三发消息给李四,其过程应该是这样的:张三发送消息,MSN服务器(中介者)接收到消息,查找李四,把消息发送到李四,同时通知张三,消息已经发送。在这里,MSN服务器就是一个中转站,负责协调两个客户端的信息交流,与此相反的就是IPMsg(也叫飞鸽),它没有使用中介者,而直接使用UDP广播的方式,每个客户端既是客户端也是服务器端。
4,中介服务
现在中介服务非常多,比如租房中介、出国中介,这些也都是中介模式的具体体现,比如你去租房子,如果没有房屋中介,你就必须一个一个小区去找,看看有没有空房子,有没有适合自己的房子,找到房子后还要和房东签合约,自己检查房屋的家具、水电煤等;有了中介后,你就省心多了,找中介,然后安排看房子,看中了,签合约,中介帮你检查房屋家具、水电煤等等。这也是中介模式的实际应用。