观察者模式是jdk使用最多的设计模式之一,有了观察者你将会消息灵通
先来认识观察者模式
我们通过举例(报纸和杂志订阅的例子)来理解观察者模式
1.报社的业务就是出版报纸
2.向某家报社订阅报纸,只要这家出版社出版报纸就会给你送来,
也就是只要你是他们的客户他们就会给你送报纸.
3.当你不想再看报纸的时候,你就取消订阅他们就不会再给你送
4.只要报社还在运营,就会一直有人向他们订阅报纸和取消订阅
同样的例子还要订桶装饮用水以及预定牛奶
但是我们要怎么来理解呢?
出版社+订阅者=观察者模式
理解了出版社和订阅者的关系也就理解了观察者模式,其实就是出版社相当于”主题(subject)”
订阅者相当于”观察者(Observer)”
订阅是随时可以取消以及订阅的忽然有一天刘某通过别人的介绍也想订阅报纸了
张三忽然发现这家的报社没有别人家的报社服务好
观察者模式定义:定义了对象之间的一对多依赖,这样一来,当一个对象改变状态的时候,它的所有依赖者都会 收到通知并自动更新.
我们的理解:观察者模式定义了一系列对象之间的一对多的关系,当一个对象改变之后其他对象都会收到通知
我们通过一个例子来分析并引入java代码
一个公司要建立一个气象监测站,这个监测站要建立在WeatherData对象上,由WeatherData负责追踪天气
状况,希望我们帮他们开发一个软件,这个软件有三种现实板分别显示目前的状况,实现气象统计及简单的预报功能,三种现实板需要实时更新.他们希望我们留下一组开房的api以后开房其他公司也可以实现气象显示板
现在我们来看看WeatherData对象
我们现在知道的有哪些呢?
1.WeatherData类具有getter方法,可以取得三个测量值(湿度、温度、气压)
2.当检测站有的数据的时MeasureMentsChanged方法就会被调用
3.我们需要实现三个需要显示气象数据的显示板
4.此系统还必须可扩展,让其他人可以增加定制的显示板
两个对象之间松耦合,他们依然可以互相交互,但是不太清楚彼此的细节
引出了一个新的设计原则:
为了交互对象之间的松偶合设计而努力
java程序代码
/**
* @author wang
* 主题
*
*/
public interface Subject {
public void RegisterObserver(Observer o);//注册观察者
public void DeleteObserver(Observer o);//删除观察者
public void NotifyObservers();//当主题状态改变时候,会调用这个方法通知观察者
}
/**
* @author wangy
* 观察者接口
*/
public interface Observer {
public void update(float temp,float humidity,float pressure);//主题改变后会把这些参数传递给观察者
//所有的观察者必须实现update方法
}
/**
* @author wangy
* 布告板显示接口
*/
public interface DisplayElement {
public void display();//当布告板需要显示时调用此方法
}
/**
* @author wangy
* 主题内容
*/
@Data
public class WeatherData implements Subject{
private float temperature;
private float pressure;
private float humidity;
private ArrayList obser;
public WeatherData(){
obser = new ArrayList();
}
@Override
public void RegisterObserver(Observer o) {
obser.add(o);
}
@Override
public void DeleteObserver(Observer o) {
int i = obser.indexOf(o);
if(i>0){
obser.remove(i);
}
}
@Override
public void NotifyObservers() {
for (int i = 0; i < obser.size(); i++) {
Observer observer = (Observer) obser.get(i);
observer.update(temperature, humidity, pressure);
}
}
public void meaurementsChanged(){
NotifyObservers();
}
public void setMeaurements(float temperature, float humidity,float pressure){
this.temperature = temperature;
this.humidity = humidity;
this.pressure = pressure;
meaurementsChanged();
}
}
public class CurrentConditionsDisplay implements Observer, DisplayElement {
private float temperature;
private float humidity;
private Subject weatherData;
public CurrentConditionsDisplay(Subject w) {
this.weatherData = w;
w.RegisterObserver(this);
}
@Override
public void display() {
System.out.println("CurrentConditionsDisplay:" + temperature + humidity);
}
@Override
public void update(float temp, float humidity, float pressure) {
this.temperature = temp;
this.humidity = humidity;
display();
}
}
public class ForecastDisplay implements Observer ,DisplayElement{
private float temperature;
private float humidity;
private Subject weatherData;
public ForecastDisplay(Subject w){
this.weatherData = w;
w.RegisterObserver(this);
}
@Override
public void display() {
System.out.println("ForecastDisplay:"+temperature+humidity);
}
@Override
public void update(float temp, float humidity, float pressure) {
this.temperature = temp;
this.humidity = humidity;
display();
}
}
public class StatisticsDisplay implements Observer ,DisplayElement{
private float temperature;
private float humidity;
private Subject weatherData;
public StatisticsDisplay(Subject w){
this.weatherData = w;
w.RegisterObserver(this);
}
@Override
public void display() {
System.out.println("StatisticsDisplay:"+temperature+humidity);
}
@Override
public void update(float temp, float humidity, float pressure) {
this.temperature = temp;
this.humidity = humidity;
display();
}
}
public class WeatherTest {
public static void main(String[] args) {
WeatherData w = new WeatherData();
CurrentConditionsDisplay curr = new CurrentConditionsDisplay(w);
ForecastDisplay fore = new ForecastDisplay(w);
StatisticsDisplay statis = new StatisticsDisplay(w);
w.setMeaurements(80, 65, 34.f);
w.setMeaurements(60, 30, 21.f);
}
}
注意:我在代码里没有getter和setter方法是因为我使用了lombok插件 详细可以百度一下
使用java内置的观察者模式
java内置了观察者模式 java.util包下的Observer和Observable和我们自己定义的两个接口非常相似
有了java内置的支持你只需要继承Observable并告诉何时通知观察者剩下的事就可以交给api来做了
和以前一样实现观察者接口(java.util.Observer)然后调用任何Observable对象的addObserver方法
不当观察者的时候调用deleteObserver方法
可观察者如何发送通知
1.调用setChanged()标记状态已经改变的事实
2.然后调用两种notifyObserver()方法中的一个notifyObervers()和notifyObservers(Object o)
观察者如何接受通知
和以前一样观察者实现更新的方法,但是方法签名不一样
update(Observable ob,Object o)
setchenged内部代码
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);
}
public void notifyObservers() {
notifyObservers(null);
}
protected synchronized void setChanged() {
changed = true;
}
protected synchronized void clearChanged() {
changed = false;
}
使用java内部观察者模式实现之前的代码
/**
* @author wangy 主题内容
*/
@Data
public class WeatherData extends Observable {
private float temperature;
private float pressure;
private float humidity;
private ArrayList obser;
public WeatherData() {
}
public void meaurementsChanged() {
setChanged();
}
public void setMeaurements(float temperature, float humidity, float pressure) {
this.temperature = temperature;
this.humidity = humidity;
this.pressure = pressure;
meaurementsChanged();
}
}
public class CurrentConditionsDisplay implements Observer, DisplayElement {
private float temperature;
private float humidity;
Observable observable;
public CurrentConditionsDisplay(Observable w) {
this.observable = w;
w.addObserver((java.util.Observer) this);;
}
@Override
public void display() {
System.out.println("CurrentConditionsDisplay:" + temperature + humidity);
}
@Override
public void update(Observable obs,Object obj) {
if(obs instanceof WeatherData){
WeatherData weatherData = (WeatherData)obs;
this.temperature = weatherData.getTemperature();
this.humidity = weatherData.getHumidity();
display();
}
}
}
java内部很多地方使用了观察者设计模式比如swing,还要GUI框架