介绍观察者模式的四大问题
- 现在的写法有什么问题吗?
- 为什么要用观察者模式?
- 什么是观察者模式?
- 观察者模式有什么好处?
采用一个案例来说明问题
- 假如现有一个检测系统,其可以检测温度,湿度等,每当检测系统更改的时候,就需要发送更改的消息到温度显示器和湿度显示器上,以便实时观测变化
目前实现思路
-
首先创建一个MonitorDate类,此类其中有DateChanged() 方法,将会在数据变化的时候自动调用(无需管怎么实现的)
-
接着创建一个update接口,创建温度类,和湿度类,分别实现此接口
-
最后在DateChanged方法中调用温度类和湿度类的update方法,以通知它们
-
监测数据类
public class MonitorDate {
private float temp;
private float humidity;
private TempDisplay tempDisplay;
private HumidityDisplay humidityDisplay;
public MonitorDate(TempDisplay tempDisplay, HumidityDisplay humidityDisplay) {
this.tempDisplay = tempDisplay;
this.humidityDisplay = humidityDisplay;
}
private void DateChanged() {
tempDisplay.update(temp, humidity);
humidityDisplay.update(temp, humidity);
}
public void setDate(float temp, float humidity) {
this.temp = temp;
this.humidity = humidity;
DateChanged();
}
}
- 更新接口
public interface Observer {
public void update(float temp, float humidity);
}
- 温度显示类
public class TempDisplay implements Observer {
@Override
public void update(float temp, float humidity) {
System.out.println("The temp is " + temp);
}
}
- 湿度显示类
public class HumidityDisplay implements Observer {
@Override
public void update(float temp, float humidity) {
System.out.println("The humidity is " + humidity);
}
}
- Main
public class Main {
public static void main(String[] args) {
TempDisplay tempDisplay = new TempDisplay();
HumidityDisplay humidityDisplay = new HumidityDisplay();
MonitorDate monitorDate = new MonitorDate(tempDisplay, humidityDisplay);
monitorDate.setDate(1.1f, 2.2f);
}
}
// out
The temp is 1.1
The humidity is 2.2
这样实现有什么问题吗?
- 对于每新增一个监测参数,都需要改代码
- 无法动态的增加减少监测显示
- 违反了设计原则之针对接口编程,而不是实现编程
什么是观察者模式
- 在对象之间定义一对多的依赖,当一个对象改变状态,依赖它的对象都会收到通知,并自动更新
接下来使用观察者模式对此进行改造
- 更新接口
public interface Observer {
public void update(float temp, float humidity);
}
- 湿度类
public class HumidityDisplay implements Observer {
private MonitorDate monitorDate;
public HumidityDisplay(MonitorDate monitorDate) {
this.monitorDate = monitorDate;
this.monitorDate.addObserver(this);
}
@Override
public void update(float temp, float humidity) {
System.out.println("The humidity is " + humidity);
}
}
- 温度类
public class TempDisplay implements Observer {
private MonitorDate monitorDate;
public TempDisplay(MonitorDate monitorDate) {
this.monitorDate = monitorDate;
this.monitorDate.addObserver(this);
}
@Override
public void update(float temp, float humidity) {
System.out.println("The temp is " + temp);
}
}
- 监测类
public class MonitorDate {
private ArrayList<Observer> observers;
private float temp;
private float humidity;
public MonitorDate() {
observers = new ArrayList<Observer>();
}
public void addObserver(Observer o) {
observers.add(o);
}
public void removeObserver(Observer o) {
observers.remove(o);
}
public void notifyObserver() {
for (int i = 0; i < observers.size(); i++) {
observers.get(i).update(temp, humidity);
}
}
public void setDate(float temp, float humidity) {
this.temp = temp;
this.humidity = humidity;
notifyObserver();
}
}
- Main
public class Main {
public static void main(String[] args) {
MonitorDate monitorDate = new MonitorDate();
TempDisplay tempDisplay = new TempDisplay(monitorDate);
HumidityDisplay humidityDisplay = new HumidityDisplay(monitorDate);
monitorDate.setDate(1.1f, 2.2f);
}
}
// out
The temp is 1.1
The humidity is 2.2
观察者模式的好处
- 松耦合
- 可在运行时增加减少通知对象
使用java自带的观察者模式
-
Observable: 等于主题 (类)
- 封装的方法
- addObserver:添加观察者
- deleteObserver:删除观察者
- notifyObservers:通知观察者
- notifyObservers(Object arg) :通知观察者,并传递参数
- setChanged:设置数据已改变(需要设置true,才会使notifyObservers生效)
- …
- …
- 封装的方法
-
Observer:等于观察者 (接口)
- update
-
需要注意的是,使用java自带的Observable进行通知会导致通知的顺序不一定
-
另外Observable是一个类,而且没有实现任何接口,这就导致了它是不能被复用的,而且其重要方法setChanged方法是protected的,这也导致了其不能被组合的方式使用,因为其实例化对象不能调用setChanged方法
-
所以自带的还是有很多的问题,如果有必要最好使用自己创建的