设计模式之观察者模式-笔记

来源:互联网 发布:腾讯算法面试题 编辑:程序博客网 时间:2024/05/16 04:48
观察者模式:定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新


设计原则:
1、为了交互对象之间的松耦合设计而努力;松耦合的设计之所以能让我们建立有弹性的OO系统,能够应对变化,是因为对象之间的互相依赖降到了最低。

场景:气象站需要实时将测量的温度、湿度信息传回,不同的显示板,根据传回的信息更新显示对应信息,显示板依赖于气象站的信息更新,而且气象站是个可扩展的气象站,可以添加删除显示板;


气象站---->主题
显示板---->观察者
主题实时更新的信息会传给所有注册过的观察者


先建立接口:
public interface Subject{
public void registerObserver(Observer o);  //用来注册观察者
public void removeObserver(Observer o);   //用来删除观察者
public void notifyObservers();    //当主题状态改变时,该方法被调用用来通知所有观察者
}

public interface Observer{
public void update(float temp, float humidity, float pressure);   //所有观察者都必须实现update()方法用来更新主题传来的信息,所有需要提供该接口,使所有观察者各自实现自己的动作细节
}

public interface DisplayElement{
public void display()   //显示板需要显示时,调用该方法,在各个观察者类中调用实现
}

实现气象站类:
public class WeatherData implements Subject{
private ArrayList observers; //用来保存所有注册了的观察者
private float temperature; //温度
private float humidity; //湿度
private float pressure; //气压

public WeatherData(){
observers = new ArrayList();
}
//将注册的观察者保存到列表中
public void registerObserver(Observer o){
observers.add(o);   
}
//删除观察者
public void removeObserver(Observer o){
int i = observers.indexOf(o);
if(i > 0){
observers.remove(i);   
}
}
//把状态通知到每个观察者,每个观察者都实现了update()方法
public void notifyObservers(){
for(int i = 0; i < observers.size(); i++){
Observer observer = (Observer)observers.get(i);
observer.update(temperature, humidity, pressure);
}
}
//当有更新是调用该方法通知每个观察者
public void measurementsChanged(){
notifyObservers();
}

//添加用来测试的方法
public void setWeatherData(float temperature, float humidity, float pressure){
this.temperature = temperature;
this.humidity = humidity;
this.pressure = pressure;
measurementsChanged();
}
}


实现显示板,显示板都需要实现update()方法和display()方法
//布告板实现类
public class CurrentConditionDisplay implements Observer,DisplayElement{
private float temperature;
private float humidity;
private Subject weatherData;

public CurrentConditionDisplay(Subject weatherData){
this.weatherData = weatherData;
weatherData.registerObserver(this);
}

public void update(float temperature, float humidity, float pressure){
this.temperature = temperature;
this.humidity = humidity;
display();
}

public void display(){
System.out.println("Current conditions:" + temperature +"F degrees and " + humidity + "% humidity);
}
}
//温度信息实现类
public class StatisticsDisplay implements Observer,DisplayElement{
private float maxTemp = 0.0f;
private float minTemp = 0.0f;
private float tempSum = 0.0f;
private int numTemperature = 0;
private Subject weatherData;

public StatisticsDisplay(Subject weatherData){
this.weatherData = weatherData;
weatherData.registerObserver(this);
}

public void update(float temperature, float humidity, float pressure){
tempSum += temperature;
numTemperature++;

if(temperature > maxTemp){
maxTemp = temperature;
}

if(temperature < minTemp){
minTemp = temperature;
}

display();
}

public void display(){
System.out.println("Avg/Max/Min temperature = " + (tempSum/numTemperature) + "/" + maxTemp + "/" + minTemp);
}
}

public class testWeatherStation{
public static void main(String[] args){
WeatherData weatherData = new WeatherData();

CurrentConditionDisplay currentDisplay = new CurrentConditionDisplay(weatherData);
StatisticsDisplay statisticDisplay = new StatisticsDisplay();

weatherData.setWeatherData(80, 69, 30.4f);
weatherData.setWeatherData(76, 58, 29.7f);
weatherData.setWeatherData(84, 66, 30.7f);
}
}

//显示结果为:
Current conditions:80 F degrees and 69% humidity
Avg/Max/Min temperature = 80.0/80.0/80.0
Current conditions:75 F degrees and 58% humidity
Avg/Max/Min temperature = 78.0/80.0/76.0
Current conditions:85 F degrees and 66% humidity
Avg/Max/Min temperature = 80.0/84.0/76.0

总结:观察者模式和策略模式类似的地方是,将需要改变的函数定义成接口,每个类都调用接口函数来实现不同的动作


对于观察者模式,java API已经有内置的观察者模式,许多功能已经事先准备好了,可以比较方便使用,它的实现和上面的实现大致相同,
具体运作的不同之处在于:
1、可观察者类中实现了 setChanged() 方法,每次向观察者发送更新的消息时,要先调用 setChange() 方法,标记状态已经改变,然后调用两种 notifyObservers() 方法中的一个(notifyObservers() 和 notifyObservers(Object arg),第二种可以传送任何的数据对象给每个观察者)
2、观察者接收更新的方法和上面的不太一样,update(Observable o, Object arg) 主题本省当做第一个变量好让观察者知道是哪个主题通知它,第二个参数正式 notifyObservers() 函数传入的数据对象,如果没有说明为空


可观察者实现 setChanged() 方法的好处,是不必在每次更新后都给观察者传递更新的信息,如气象站只想在温度变化超过半度再给观察者传递更新的信息,这样就可以通过setChanged函数来控制更新的传递


使用java API内置的观察者模式的实现如下:
import java.util.Observable; //可观察者(即上面实现的主题)
import java.util.Observer;  //观察者

//气象站类,继承了超类Observable
public class WeatherData extends Observable{
private float temperature;
private float humidity;
private float pressure;

public WeatherData(){}

public void measurementsChanged(){
setChange();
notifyObservers();
}

public void setWeatherData(float temperature, float humidity, float pressure){
this.temperature = temperature;
this.humidity = humidity;
this.pressure = pressure;
}

public float getTemperature(){
return temperature;
}

public float getHumidity(){
return humidity;
}

public float getPressure(){
return pressure;
}


//布告板类 
import java.util.Observable;
import jave.util.Observer;

public class CurrentConditionDisplay implements observer,DisplayElement{
Observable observable;
private float temperature;
private float humidity;

public CurrentConditionDisplay(Observable observable){
this.observable = observable;
observable.addObserver(this);
}
//upate()中,要先确定观察者属于WeatherData类型,然后利用getter方法获取温度和湿度值
public void update(Observable obs, Object arg){
if(obs instanceof WeatherData){
WeatherData weatherData = (WeatherData)obs;
this.temperature = weatherData.getTemperature();
this.humidity = weatherData.getHumidity();
display();
}
}

public void display(){
System.out.println("Current conditions:" + temperature +"F degrees and " + humidity + "% humidity);
}
}


java API 中内置的观察者模式中可观察者 Observable 是一个类,所以必须设计一个类来继承它,如果某个类想同时具有它和另一个超类的行为,就无法实现,因为java不支持多重继承,还有就是没有Observable接口,所以无法建立自己的实现和java 内置的Observer API搭配使用,也无法将java.util 的实现换成另一套做法的实现

要点:
1、观察者模式定义了对象之间一对多的关系
2、主题用一个共同的接口来更新观察者
3、观察者和可观察者之间用一种松耦合方式结合,可观察者不知道观察者的细节,只知道观察者实现了观察者接口
4、使用此模式时,可以从被观察者处推(push)或者拉(pull)数据
5、有多个观察者时,不可以依赖特定的通知次序



原创粉丝点击