行为型模式
目录
1、中介者模式(Mediator Pattern)
说起来也简单、好理解。生活中我们租房经常都是通过中介来实现的。一般租房要么是房东直租要么是中介。那么今天要讲的中介者模式和租房的这个中介是否有关系呢?当然是有点关系的。中介者模式是用来降低多个对象和类之间的通信复杂性。这种模式提供了一个中介类,这个类就来处理不同类之间的通讯。租房中介也是这个道理。复制与各个房东和租户之间的通讯。将多对多简化成了一对多的关系。我们下面来具体看看到底是怎么回事吧!
用来降低多个对象和类之间的通信复杂性。这种模式提供了一个中介类,该类通常处理不同类之间的通信,并支持松耦合,使代码易于维护。
- 意图:用一个中介对象来封装一系列的对象交互,中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。
- 主要解决:对象与对象之间存在大量的关联关系,这样势必会导致系统的结构变得很复杂,同时若一个对象发生改变,我们也需要跟踪与之相关联的对象,同时做出相应的处理。
- 何时使用:多个类相互耦合,形成了网状结构。
- 如何解决:将上述网状结构分离为星型结构。
- 关键代码:对象 Colleague 之间的通信封装到一个类中单独处理。
1.1 中介者模式UML图
UML图如下:
1.2 日常生活中看中介者模式
例如:世界上各个国家的和平和安全,沟通和交流等等问题,如果各个国家都可以互相交互的话,容易造成混乱,关系复杂。这个时候联合国的作用就出现了,联合国作为一个中介对象来维护各个国家的和平和安全等等的工作。
- 1、中国加入 WTO 之前是各个国家相互贸易,结构复杂,现在是各个国家通过 WTO 来互相贸易。
- 2、机场调度系统。
- 3、MVC 框架,其中C(控制器)就是 M(模型)和 V(视图)的中介者。
1.3 Java代码实例
这里以公司各部门之间交互,使用中介者(总经理)的方式来代码实现。
首先定义一个抽象中介者(Mediator)对象:这里使用一个接口来定义
//抽象中介者
public interface Mediator {
void register(String dname,Department d);//将具体的同事类注册到中介者中,让中介者知道所有的同事。以便进行交互
void command(String dname);//通过部门名称,发出命令
}
再定义一个抽象同事类(Colleague):仍然使用一个接口来定义
//抽象同事类:部门
public interface Department {
void selfAction();//做本部门的事
void outAction();//向总经理发出申请
}
然后可以开始定义具体的实现了,先定义抽象同事的具体实现(ConcreteColleague)
研发部:
//具体同事类:研发部
public class Development implements Department{
private Mediator m;//中介者(总经理)
//构造的时候将中介者构造进来
public Development(Mediator m) {
super();
this.m = m;
//ConcreteMediator(具体中介者对象):实现抽象中介者的方法
//它需要知道所有具体同事类,并从具体同事接收消息,向具体同事对象发出命令。
m.register("development", this);//将当前部门对象注册到中介者对象中,
}
@Override
public void selfAction() {
System.out.println("研发部:正在研发项目......");
}
@Override
public void outAction() {
System.out.println("研发部向总经理说:项目经费没了.....");
}
}
财务部:
//具体同事类:财务部
public class Finacial implements Department{
private Mediator m;//中介者(总经理)
//构造的时候将中介者构造进来
public Finacial(Mediator m) {
super();
this.m = m;
//ConcreteMediator(具体中介者对象):实现抽象中介者的方法
//它需要知道所有具体同事类,并从具体同事接收消息,向具体同事对象发出命令。
m.register("finacial", this);//将当前部门对象注册到中介者对象中,
}
@Override
public void selfAction() {
System.out.println("财务部:会计正在核对财务......");
}
@Override
public void outAction() {
System.out.println("财务部向总经理说:钱很多,花不完.....");
}
}
市场部:
//具体同事类:市场部
public class Market implements Department{
private Mediator m;//中介者(总经理)
//构造的时候将中介者构造进来
public Market(Mediator m) {
super();
this.m = m;
//ConcreteMediator(具体中介者对象):实现抽象中介者的方法
//它需要知道所有具体同事类,并从具体同事接收消息,向具体同事对象发出命令。
m.register("market", this);//将当前部门对象注册到中介者对象中,
}
@Override
public void selfAction() {
System.out.println("市场部:正在跑市场......");
}
@Override
public void outAction() {
System.out.println("市场部向总经理说:合同已搞定,需财务部报销.....");
m.command("finacial");//通过总经理这个中介,向总经理发出申请,告知需要跟财务部交互报销经费
}
}
注意这里!!! m.command(
"finacial"
); 这里通过总经理这个中介者对象,向财务部发出了申请。
通过中介者对象和财务部交互而没有直接跟财务部打交道
定义具体的中介者(ConcreteMediator):总经理
//中介者的具体实现:总经理
public class President implements Mediator{
//总经理也需要知道所有具体同事类
private Map<String,Department> map = new HashMap<String,Department>();
@Override
public void register(String dname, Department d) {
map.put(dname, d);//将同事注册到总经理的所有同事类容器中
}
@Override
public void command(String dname) {
map.get(dname).selfAction();//根据部门名称向具体的部门下命令
}
}
现在开始测试:
市场部需要向财务部发出申请,这时候就可以通过中介者(总经理)来向财务部发出申请了。而不是直接调用财务部的方法
public static void main(String[] args) {
Mediator m = new President();//构建中介者对象:总经理
Market market = new Market(m);//构建市场部
market.selfAction();
market.outAction();//市场部和财务部交互
}
输出结果:
市场部:正在跑市场......
市场部向总经理说:合同已搞定,需财务部报销.....
财务部:会计正在核对财务......
2、中介者模式在JDK源码中体现
打开 JDK 中的 Timer 类,查看 Timer 类的结构,会发现 Timer 类中有很多 schedule() 重载方法,如下图所示。
任意点开其中一个方法,会发现所有方法最终都调用了私有的 sched() 方法,源码如下。
public class Timer {
...
public void schedule(TimerTask task, long delay) {
if (delay < 0)
throw new IllegalArgumentException("Negative delay.");
sched(task, System.currentTimeMillis()+delay, 0);
}
...
private void sched(TimerTask task, long time, long period) {
if (time < 0)
throw new IllegalArgumentException("Illegal execution time.");
// Constrain value of period sufficiently to prevent numeric
// overflow while still being effectively infinitely large.
if (Math.abs(period) > (Long.MAX_VALUE >> 1))
period >>= 1;
synchronized(queue) {
if (!thread.newTasksMayBeScheduled)
throw new IllegalStateException("Timer already cancelled.");
synchronized(task.lock) {
if (task.state != TimerTask.VIRGIN)
throw new IllegalStateException(
"Task already scheduled or cancelled");
task.nextExecutionTime = time;
task.period = period;
task.state = TimerTask.SCHEDULED;
}
queue.add(task);
if (queue.getMin() == task)
queue.notify();
}
}
...
}
不论是什么样的任务加入到队列中,我们都把这个队列中的对象称为“同事”。查看 sched() 方法的源码可以看出,所有的任务(task)都放到了 Timer 类维护的 task 队列中,同事之间的通信都是通过 Timer 来协调完成的,所以,Timer 承担了中介者的角色,而 task 队列内的任务就是具体同事对象。
3、中介者模式优缺点
3.1 优点
- 1、降低了类的复杂度,将一对多转化成了一对一。
- 2、各个类之间的解耦。
- 3、符合迪米特原则。
3.2 缺点
- 中介者会庞大,变得复杂难以维护。
- 新增一个对象类,需要修改抽象中介者和具体中介者类。
3.3 使用场景
- 1、系统中对象之间存在比较复杂的引用关系,导致它们之间的依赖关系结构混乱而且难以复用该对象。
- 2、想通过一个中间类来封装多个类中的行为,而又不想生成太多的子类。
3.4 注意事项
不应当在职责混乱的时候使用。
参考文章:
http://m.biancheng.net/view/8496.html