介绍 :
-
主题和观察者是一对多的关系 建立一套触发机制 当主题数据发生改变时 通知观察者数据已更新
-
缺点 : 1.当观察者多时 通知到所有观察者的时间会变长 2.观察者并不知道主题是如何变化的 仅仅知道主题发送了改变
-
类图如下
这里我们以报社为例 报社是主题 订阅报纸的是观察者
- 我们如果需要报纸 就需要到报社去订阅 此时在代码里 需要一个注册方法把观察者注册进去 当我们订阅一段时间后突然不想看了 就需要告诉报社 以后不要继续给我送报纸了 那么使用代码实现就是一个删除观察者的方法 当报社有新消息时 需要通知观察者 那么还需要一个通知方法 代码实现如下
public interface Subject {
//注册方法
void registerObserver(Observer o);
//取消注册
void remoteObserver(Observer o);
//主题改变时通知观察者
void notifyObserver();
}
========================
public class WeatherData implements Subject {
private ArrayList<Observer> observerList;//存储所有观察者
//下面是主题状态 当状态修改时 去通知观察者
private float temperature;//温度
private float humidity;//湿度
private float pressure;//压力
public WeatherData() {
this.observerList = new ArrayList<Observer>();
}
//注册
@Override
public void registerObserver(Observer o) {
observerList.add(o);
}
//取消注册
@Override
public void remoteObserver(Observer o) {
observerList.remove(o);
}
//通知
@Override
public void notifyObserver() {
for (Observer o : observerList) {
o.update(temperature,humidity,pressure);
}
}
//当主题数据变化时 通知观察者
public void measurementChange(){
notifyObserver();
}
//模拟修改主题数据
public void setMeasureMent(float temperature, float humidity, float pressure) {
this.temperature = temperature;
this.humidity = humidity;
this.pressure = pressure;
measurementChange();
}
}
- 以上是主题实现 接下来我们来看看观察者的实现
- 观察者只需要被动接收数据集合 订阅报纸不需要每天都去报社去问有没有新消息 而是报社主动去通知你
- 在这里 我们在通知观察者时是一个方法 而观察者要查看数据时提供一个方法 可以根据自己需要把2个方法合并为一个方法
public interface Observer {
/**
* 当数据发送改变时主题会把这些状态值作为方法参数 发送给观察者
* @param temp
* @param humidity
* @param pressure
*/
void update(float temp,float humidity,float pressure);
}
========
public interface Displayelement {
void display();
}
========
public class CurrentConditionDisplay implements Observer, Displayelement {
private float temperature;//温度
private float humidity;//湿度
private float pressure;//压力
//注册自己到主题
public CurrentConditionDisplay(Subject weatherData) {
weatherData.registerObserver(this);
}
@Override
public void update(float temp, float humidity, float pressure) {
this.temperature = temp;
this.humidity = humidity;
this.pressure = pressure;
display();
}
@Override
public void display() {
System.out.println("CurrentConditionDisplay{" +
"temperature : " + temperature +
", humidit : " + humidity +
", pressure : " + pressure +
'}');
}
}
- 测试
public class Test {
public static void main(String[] args) {
WeatherData weatherData = new WeatherData();//创建主题
CurrentConditionDisplay current = new CurrentConditionDisplay(weatherData);//创建观察者并注册到主题
//修改主题数据
weatherData.setMeasureMent(1.0f,2.0f,3.3f);
weatherData.remoteObserver(current);
weatherData.setMeasureMent(1.0f,2.0f,3.3f);
}
}
以上为我们自定义实现 在java中也提供了观察者的接口和主题类供我们使用
- 在这里主题继承Observable类
public class weather extends Observable {
/**
* 修改changed属性为true 此时才会通知观察者 否则不会
*/
@Override
public void setChanged() {
super.setChanged();
}
/**
* 修改changed属性为false
*/
@Override
public void clearChanged() {
super.clearChanged();
}
}
- 观察者实现Observer接口
public class Current implements Observer {
/**
* arg : 通知消息
*/
@Override
public void update(Observable o, Object arg) {
System.out.println(o + "--" + arg);
}
}
- 测试
public class Demo {
public static void main(String[] args) {
weather weather = new weather();
Current current = new Current();
weather.addObserver(current);
weather.setChanged();
weather.notifyObservers("11111");
}
}