定义
观察者模式(Observer Pattern):定义对象之间的一种一对多依赖关系,使得每当一个对象状态发生改变时,其相关依赖对象皆得到通知并被自动更新。观察者模式的别名包括发布-订阅(Publish/Subscribe)模式、模型-视图(Model/View)模式、源-监听器(Source/Listener)模式或从属者(Dependents)模式。
通俗理解
“敌不动,我不动,敌若动,我先动”,这是《兵法》一个经典的战略,意思是说,在战场上,我们要注意好敌军的动向,根据敌军的动向来指定自己这一方的作战方针,如果敌人不行动,我们就按兵不动,如果敌人行动,我们就需要比敌人更先行动。这一句话后来被教员融合当时在社会斗争情况总结为"敌来我走,敌驻我扰,敌退我追"!这也是根据敌人的行动来执行自己的战略。
类似于这种,根据敌人的行动类改变自己的方针,就是观察者模式最好的诠释。当敌人行动的时候,他的状态改变了,那么也会影响到我军的状态。当然,在观察者模式当中,定义的是一对多的依赖关系,这在生活中的含义就是,当一军行动的时候,会引起联合军队的行动。
这样的例子,不仅仅存在战场上,在我们生活中也是如此。红绿灯变绿的时候,所有的汽车都会开动;当号令枪响的时候,所有的运动员都会健步如飞;当下暴雨的时候,所有的人都会躲雨。
示例
业务为红绿灯变绿的时候,所有的汽车都会开动。
渣渣程序
红绿灯
public class TrafficLight {
private ELightType eLightType;
private Car car;
public TrafficLight(Car car) {
this.car = car;
}
public void becomeGreen() {
eLightType = ELightType.GREEN;
System.out.println("交通灯变绿了"+eLightType);
}
public void becomeYellow() {
eLightType = ELightType.YELLOW;
System.out.println("交通灯变黄了"+eLightType);
}
public void becomeRed() {
eLightType = ELightType.RED;
System.out.println("交通灯变红了"+eLightType);
}
public void notifyCar() {
switch (eLightType) {
case RED:car.stop();break;
case GREEN:car.move();break;
case YELLOW:car.stop();break;
default:car.stop();
}
}
public enum ELightType {
GREEN,YELLOW,RED
}
}
车辆
public class Car {
private boolean isMove = false;
//setter、getter方法省略
public void move() {
isMove = true;
System.out.println("汽车开动了"+isMove);
}
public void stop() {
isMove = false;
System.out.println("汽车停止了"+isMove);
}
}
程序入口
public class Main {
public static void main(String[] args) {
TrafficLight trafficLight = new TrafficLight(new Car());
trafficLight.becomeGreen();
trafficLight.notifyCar();
}
}
//交通灯变绿了GREEN
//汽车开动了true
上面基本上是实现了观察者模式的理念,但是演示了什么叫不面向接口编程,什么叫紧耦合。存在如下问题:
- 红绿灯和车辆是紧耦合的,如果我需要添加行人监听,那么我就需要修改交通灯的类,不利于扩展;
- 车辆(订阅者)的类的更新方法复杂,没有统一接口,如果添加行人的更新状态根本是不可能的。
- 这里提示车辆更新的方法只传递了一个类型,如果这个类型十分复杂的情况下,那么参数很难搞定。
优化
类图
程序
观察者接口与车辆实现
public interface IObserver {
void update(ISubject subject, Object args);
}
public class Car implements IObserver {
private boolean isMove = false;
// 省略setter、getter方法
public void move() {
isMove = true;
System.out.println("汽车开动了"+isMove);
}
public void stop() {
isMove = false;
System.out.println("汽车停止了"+isMove);
}
@Override
public void update(ISubject subject, Object args) {
TrafficLight.ELightType type = (TrafficLight.ELightType) args;
update(type);
}
public void update(TrafficLight.ELightType type) {
switch (type) {
case RED:stop();break;
case GREEN:move();break;
case YELLOW:stop();break;
default:stop();
}
}
}
被观察对象的接口与交通灯实现
public interface ISubject {
void addObserver(IObserver observer);
void removeObserver(IObserver observer);
void removeObservers();
void notifyObservers(Object args);
void notifyObservers();//模式里面没有这个方法
}
public class TrafficLight implements ISubject{
private LinkedTransferQueue<IObserver> observers;
public TrafficLight() {
this.observers = new LinkedTransferQueue<>();
}
private ELightType eLightType;
public ELightType geteLightType() {
return eLightType;
}
public void seteLightType(ELightType eLightType) {
this.eLightType = eLightType;
}
public void becomeGreen() {
eLightType = ELightType.GREEN;
System.out.println("交通灯变绿了"+eLightType);
}
public void becomeYellow() {
eLightType = ELightType.YELLOW;
System.out.println("交通灯变黄了"+eLightType);
}
public void becomeRed() {
eLightType = ELightType.RED;
System.out.println("交通灯变红了"+eLightType);
}
@Override
public void addObserver(IObserver observer) {
this.observers.add(observer);
}
@Override
public void removeObserver(IObserver observer) {
this.observers.remove(observer);
}
@Override
public void removeObservers() {
this.observers.clear();
}
@Override
public void notifyObservers(Object args) {
for(IObserver observer : observers) {
observer.update(this, args);
}
}
@Override
public void notifyObservers() {
notifyObservers(eLightType);
}
public enum ELightType {
GREEN,YELLOW,RED
}
}
程序入口
public class Main {
public static void main(String[] args) {
ISubject trafficLight = new TrafficLight();
IObserver car = new Car();
trafficLight.addObserver(car);
((TrafficLight) trafficLight).becomeGreen();
trafficLight.notifyObservers();
}
}
//交通灯变绿了GREEN
//汽车开动了true
通过上面的过程,如果我们需要添加一个新的订阅者,那么只需要添加一个新的订阅者并实现IObserver
,然后写上相关的update
方法就可以,而且这种方式可以增加多个订阅者,不像一开始一样,就只能绑定一个订阅者。
优点
- 对象之间的同步通信;
- 可以通知一个或多个关联对象;
- 对象之间的关系以松耦合关联,不互相一样,增加订阅者类的时候只需要扩展添加新类即可。
缺点
- 松耦合导致代码不清晰,难理解;
- 通知多个订阅者浪费时间,而且可能会出现系统崩溃等情况;
- 如果是异步通知的话,不能保证通知到位;
- 通知者并不知道是否通知到位。
应用场景
- 监听事件驱动程序设计中的外部事件;
- 监听/监视某个对象的变化;
- 发布/订阅者模型。
实例
- JDK的java.util.Observable和java.util.Observer接口;
- MVC模型。