一、自定义观察者模式
需要subject类 (一)以及Observer类(多)
subject 主要功能是接收数据以及通知变更观察者(Observer)。
observer 主要功能是接收变更后的数据,一定实现update接口。
核心:subject管理所有观察者,当数据变更时通知所用观察者(就是调用update)
subject接口类:
public interface ISubject {
void registerObservers(IObervers oberver);//注册观察者
void removeObservers(IObervers oberver);//删除观察者
void notifyObservers();//变更通知
}
subject具体实现类:
public class Subject implements ISubject {
private List obervers;
private Weather weather;
public Subject() {
obervers = new ArrayList<>();
weather = new Weather();
}
@Override
public void registerObservers(IObervers oberver) {
obervers.add(oberver);
}
@Override
public void removeObservers(IObervers oberver) {
int index = obervers.indexOf(oberver);
if (index >= 0) {
obervers.remove(oberver);
}
}
@Override
public void notifyObservers() {
for (IObervers oberver : obervers) {
oberver.update(weather);
}
}
public void setNewWeatherData(double temp, double humidity) {
weather.setHumidity(humidity);
weather.setTemp(temp);
notifyObservers();
}
}
数据封装类:
public class Weather {
private double temp;
private double humidity;
public double getTemp() {
return temp;
}
public void setTemp(double temp) {
this.temp = temp;
}
public double getHumidity() {
return humidity;
}
public void setHumidity(double humidity) {
this.humidity = humidity;
}
}
观察者接口类:(update很关键)
public interface IObervers {
void update(Weather weather);
}
观察者具体实现类:
public class Display implements IObervers {
private Weather weather;
public Display(ISubject subject) {
subject.registerObservers(this);
}
public void display() {
System.out.println("温度:" + weather.getTemp());
}
@Override
public void update(Weather weather) {
this.weather = weather;
}
public static void main(String[] args) {
Subject subject = new Subject();
Display display = new Display(subject);
subject.setNewWeatherData(1.1, 60);
display.display();
}
}
上面就是简单的例子,需要创建主题,创建观察者并注册,主题数据变化,观察者显示。
二、利用Java内置观察者模式
主题类:
Observable为 java.util.Observable;,类似上面的subject,里面管理了注册,删除,更新。我们只需要在变更的时候先调用
setChanged(); 方法说明数据改变了,再调用notifyObservers(); 超类会自行更新。切记:此类要实现数据的get方法(如下getWeather()),以此来获取数据,不用想上面的传来传去。
package com.rkt.demo.observer2;
import com.rkt.demo.observers.Weather;
import java.util.Observable;
public class MySubject extends Observable {
private Weather weather;
public void setNewWeatherData(double temp, double humidity) {
weather = new Weather();
weather.setHumidity(humidity);
weather.setTemp(temp);
setChanged();
notifyObservers();
}
public Weather getWeather() {
return weather;
}
}
观察者类
实现Observer 接口
import java.util.Observable;
import java.util.Observer;
public class MyDisplay implements Observer {
private Weather weather = new Weather();
public MyDisplay(Observable subject){
subject.addObserver(this);
}
@Override
public void update(Observable o, Object arg) {
if (o instanceof MySubject) {
MySubject subject = (MySubject) o;
weather = subject.getWeather();
}
}
public void display() {
System.out.println("温度:"+weather.getTemp());
}
public static void main(String[] args) {
MySubject subject=new MySubject();
MyDisplay myDisplay=new MyDisplay(subject);
subject.setNewWeatherData(1.2, 30);
myDisplay.display();
}
}
可能会有一点疑问,数据改变时怎么通知的观察者;
看下超类源码,将自己直接仍回观察者,然后观察者通过主题的get方法获取数据类(这就是上面为什么一定要实现数据类的get方法)
public void notifyObservers(Object arg) {
Object[] arrLocal;
synchronized (this) {
if (!changed)
return;
arrLocal = obs.toArray();
clearChanged();
}
for (int i = arrLocal.length-1; i>=0; i--)
((Observer)arrLocal[i]).update(this, arg);
}