观察者模式

来源:互联网 发布:淘宝里的优惠券怎么用 编辑:程序博客网 时间:2024/04/26 02:46

(本文中一些例子和定义均摘自《Head First 设计模式》)

“观察者模式:定义了对象之间的一对多的依赖,这样一来,当一个对象改变状态的时候,它的所有依赖者都会收到通知并自动更新。”

举例,天气情况报告。

我们有很多不同的表示天气预报的公告栏,当天气情况发生变化的时候,这些公告栏都能够接收到变化的通知,并且自动的根据变化而变化。

当观察者不需要再订阅主题的时候,能够退订主题。这样天气预报变化的情况就不会再通知它。

 

步骤:

1.  主题接口

 

public interface Subject {
//注册观察者
    public void registerObserver(Observer o);
//注销观察者
    public void removeObserver(Observer o);
//通知所有的观察者
    public void notifyObservers();
}

 2.  观察者接口

public interface Observer {
//对主题的变化情况,做更新

    public void update(float temperature, float humidity, float pressure);
}

3.  显示接口

public interface DisplayElement {
    
//观察者通过此接口来显示信息
    public void display();
}

 4. 对具体的主题,实现主题接口

import java.util.ArrayList;

public class WeatherData implements Subject {
    @SuppressWarnings(
"unchecked")
    
private ArrayList observers;
    
private float temperature;
    
private float humidity;
    
private float pressure;
    @SuppressWarnings(
"unchecked")
    
public WeatherData() {
        observers 
= new ArrayList();
    }

    @Override
    
public void notifyObservers() {
        
for(int i = 0; i < observers.size(); i++{
            Observer observer 
= (Observer)observers.get(i);
            observer.update(temperature, humidity, pressure);
        }


    }


    @SuppressWarnings(
"unchecked")
    @Override
    
public void registerObserver(Observer o) {
        observers.add(o);

    }


    @Override
    
public void removeObserver(Observer o) {
        
int i = observers.indexOf(o);
        
if(i <= 0{
            observers.remove(i);
        }


    }

    
    
public void measurementsChanged() {
        notifyObservers();
    }

    
    
public void setMeasurements(float temperure, float humidity, float pressure) {
        
this.temperature = temperure;
        
this.humidity = humidity;
        
this.pressure = pressure;
        measurementsChanged();
    }


}

5. 建立布告栏,也就是我们的观察者,实现观察者接口

public class CurrentConditionsDisplay implements Observer, DisplayElement {
    
private float temperature;
    
private float humidity;
    
private Subject weatherData;
    
    
public CurrentConditionsDisplay(Subject weatherData) {
        
this.weatherData = weatherData;
        weatherData.registerObserver(
this);
    }

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

    }


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

    }


}

这样整个基本的模型就搭建完成。接下来测试一下

public class WeatherStation {
    
public static void main(String[] args) {
        WeatherData weatherData 
= new WeatherData();
        CurrentConditionsDisplay currentDisplay 
= new CurrentConditionsDisplay(weatherData);
        weatherData.setMeasurements(
1008090);
        currentDisplay.display();
    }

}

 

可以发现,当主题(weatherData)发生变化的时候,观察者(currentDisplay)收到变化的通知,并且随着主题的变化而变化。

 

JAVA内置的观察者模式

 

一个被观测的对象必须服从下面的两个简单规则。第一,如果它被改变了,它必须调用setChanged( )方法。第二,当它准备通知观测程序它的改变时,它必须调用notifyObservers( )方法。这导致了在观测对象中对update( )方法的调用。注意——当对象在调用notifyObservers( )方法之前,没有调用setChanged( )方法,就不会有什么动作发生。在update( )被调用之前,被观测对象必须调用setChanged( )和notifyObservers( )两种方法 

Observable中有两个重载的方法,一个是不带参数的notifyObservers(),一个是带参数的notifyObservers(Object arg)
先说那个带参数的notifyObservers(Object arg):
这个参数Object arg 其实就是 Observer接口中的update(Observable o, Object arg)方法中的第二个参数
其实就是一个数据对象,也就是通知观察者,改变的数据对象是什么
这就是一种PUSH的方法,由主题主动的PUSH需要改变的数据对象给观察者
例子:
public class WeatherData extends Observable {
         
private float temperature;    
         
private float humidity;
         
private float pressure;

         ……..
          
public void measurementsChanged() {
        setChanged();
        notifyObservers(
float temperature);
    }

}

public class CurrentDisplay extends Observer {
         
private float temperature;    
         
private float humidity;
         
private float pressure;

         ……..
         
public void update(Observable obs,Object arg) {
    
if(arg instanceof Float){
             temperature 
= ((Float)arg).floatValue();
    }

}

而第二种不带参数的notifyObservers(),当调用它的时候, 传递一个null的数据对象给观察者.

其实也就是说,观察者需要改变什么数据,是需要观察者自己到主题那里去pull.
也就是说,通知你主题发生了变化,但是具体需要什么变化的数据,由你自己决定.
例子:
public class WeatherData extends Observable {
         
private float temperature;    
         
private float humidity;
         
private float pressure;

……..
         
public void measurementsChanged() {
        setChanged();
        notifyObservers();
    }

          
public float getTemperature(){
    Return temperature;
}
 
}

public class CurrentDisplay extends Observer {
         
private float temperature;    
         
private float humidity;
         
private float pressure;

……..
          
public void update(Observable obs,Object arg) {
    
if(obs instanceof WeatherData){
        WeatherData weatherData 
= (WeatherData)obs;
        This.temperature 
= weatherData.getTemperature();
    }

 
}

JAVA内置观察者模式不足之处:

Observable是一个类,这样的话就必须要继承它才能实现主题的功能。当你想从一个超类中继承实现这个功能就不可能了。并且Observable将关键方法setChanged()给保护起来了,也就是说如果你不继承Observable就无法创建实例到自己的对象中。
原创粉丝点击