生活中的例子
我们每天都会过马路,当十字路口有红绿灯时,我们只需要等绿灯亮就可以安心的走了。但是如果没有红绿灯,我们在过马路时就需要仔细多了。我们需要不停的观察路上行驶的车辆,小心谨慎的走,直到穿过马路。
将上面的例子类比到代码的世界里,不管是人还是车辆都可以算作是对象。当这些对象要穿过十字路口时,如果没有红绿灯,那就需要彼此引用,不断的判断彼此的状态,这样就相当复杂了。但是如果有了红绿灯就不一样了。当有了红绿灯后,车辆、行人就不需要观察彼此的状态了。大家都看红绿灯即可,红灯停绿灯行。
在这个例子中,红绿灯就是一个调停者。
调停者说明
调停者模式包装了一系列对象相互作用的方式,使得这些对象不必明显引用。从而使他们可以比较松散的耦合,而且可以独立的改变他们之间的交互。
代码样例
接下来,我们通过代码来看看调停者模式是如何工作的
网上很多调停者都是用在UI组件或者聊天室的demo中的
首先我们定义调停者,也就是红绿灯
/**
* 信号灯,调停者接口,方便替换调停者
* @author skyline
*/
public interface SignalLamp {
boolean canGo(Direction direction);
}
/**
* 红绿灯,最最简单的那种红绿灯
* @author skyline
*/
public class TrafficLights implements SignalLamp {
/**
* 状态,0红灯亮,东西方向的车不能走,1绿灯亮,东西方向的车可以走
*/
private int status;
/**
* 状态,0红灯亮,东西方向的车不能走,1绿灯亮,东西方向的车可以走
*
* @param status
*/
public void setStatus(int status) {
this.status = status;
}
@Override
public boolean canGo(Direction direction) {
if (status == 1) {
return direction == Direction.EW;
} else {
return direction == Direction.SN;
}
}
@Override
public String toString() {
return "TrafficLights{" +
"status=" + status +
'}';
}
}
然后我们定义路上的车辆
/**
* 抽象汽车
* @author skyline
*/
public abstract class Car {
Direction direction;
SignalLamp signalLamp;
Car(Direction direction, SignalLamp signalLamp) {
this.direction = direction;
this.signalLamp = signalLamp;
}
public abstract void go();
}
/**
* 公交车,汽车的一种
* @author skyline
*/
public class Bus extends Car {
Logger logger = LoggerFactory.getLogger(Bus.class);
public Bus(Direction direction, SignalLamp signalLamp) {
super(direction, signalLamp);
}
@Override
public void go() {
if (signalLamp.canGo(direction)) {
logger.info("[{}]gogogo", this);
} else {
logger.info("[{}]can not go", this);
}
}
@Override
public String toString() {
return "Bus{" +
"direction=" + direction +
", signalLamp=" + signalLamp +
"} ";
}
}
/**
* 小轿车,汽车的一种
* @author skyline
*/
public class Sedan extends Car {
Logger logger = LoggerFactory.getLogger(Sedan.class);
public Sedan(Direction direction, SignalLamp signalLamp) {
super(direction, signalLamp);
}
@Override
public void go() {
if (signalLamp.canGo(direction)) {
logger.info("[{}]gogogo", this);
} else {
logger.info("[{}]can not go", this);
}
}
@Override
public String toString() {
return "Sedan{" +
"direction=" + direction +
", signalLamp=" + signalLamp +
"} ";
}
}
/**
* 大卡车
* @author skyline
*/
public class Truck extends Car {
Logger logger = LoggerFactory.getLogger(Truck.class);
public Truck(Direction direction, SignalLamp signalLamp) {
super(direction, signalLamp);
}
@Override
public void go() {
if (signalLamp.canGo(direction)) {
logger.info("[{}]gogogo", this);
} else {
logger.info("[{}]can not go", this);
}
}
@Override
public String toString() {
return "Truck{" +
"direction=" + direction +
", signalLamp=" + signalLamp +
"} ";
}
}
最后,我们看下Main方法
public class Main {
public static void main(String[] args) {
TrafficLights trafficLights = new TrafficLights();
trafficLights.setStatus(0);
Bus bus = new Bus(Direction.EW, trafficLights);
Sedan sedan = new Sedan(Direction.SN, trafficLights);
Truck truck = new Truck(Direction.EW, trafficLights);
bus.go();
sedan.go();
truck.go();
}
}
结果
总结
- 从Main方法的逻辑中可以看到,各个车辆之间行驶方向不同,但是都调用了
go
方法 - 具体能不能行驶由
TrafficLights
来进行判断 - 如果没有
TrafficLights
,那每辆车之间需要相互引用,然后再在go方法中判断各种可能的情况,判断后才能知道能不能行驶 - 调停者的引入简化了多个对象之间的关系,由原来的多对多简化为一对一
- 调停者模式并不是发布订阅,个人感觉调停者需要负责一定的业务逻辑,而发布订阅中的Message不需要执行业务逻辑
- 在上面的例子中,如果红绿灯换成那种有单独转向灯的信号灯,原有的车辆对象不需要修改,只需要替换
TrafficLights
就可以了。 - 这种设计模式需要谨慎使用,如果设计不当,调停者对象可能会演化为上帝对象,最终难以维护。
- 调停者模式的用途是管理很多对象的相互作用,以便这些对象可以专注于自身的行为,而独立于其他对象。