设计模式入门-观察者模式(二)

      今天有空,来解决一下所写的上一篇《观察者模式》中残留的问题。上一篇文章地址是 《观察者模式》

     在上一篇文章中,我们自己定义了观察者模式中的主题接口Subject,观察者接口Observer,然后通过实现该主题接口得到了WeatherData类,实现观察者接口得到三个观察者(布告板):当前天气布告板CurrentConditionDisplay,天气统计布告板StatisticsDiaplay,预告天气布告板ForecastDisplay。这三个类的对象通过向主题对象WeatherData注册成为观察者后,主题可以适时的调用update函数将自身的内部属性的值传给观察者,这样就可以更新观察者了。

     来简单看一下代码:

     主题对象中通过调用update来更新每一个观察者

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

      观察者CurrentConditionDisplay中的update函数中使用主题对象传入的参数来完成更新。

 @Override  
    public void update(float temp, float humidity, float pressure) {  
        this.temperature=temp;  
        this.humidity=humidity;  
        this.pressure=pressure;  
        System.out.println("当前天气状态 :"+temperature+"度 , "+humidity+  
                "湿度 和 "+pressure+"帕");  
    }  

在这里,我们会发现一个问题:主题对象WeatherData每次传的参数只能是temperature,humidity,pressure三个。假如观察者并不需要所有的参数呢。所以说有可能某观察者只需要主题的部分数据,但主题每次把许多无用的值都传入了。

那么如何解决这个问题呢?主题可以开放一些访问其内部属性值的接口,观察者通过该接口自己去取它所需要的数据的。这样做是有必要的,因为每个观察者都有可能是不一样的,那么他们所需要的数据也是不一样的,主题不可以直接把所有的值传给他们。这种方式称为pull(拉)。

Java内置的观察者模式提供了push(推)和pull(拉)两种方式。

运行机理:

    1、主题如何来实现    

     通过继承Observable来实现自定义的主题类,我们来看一下Observable类中有哪些函数。

void addObserver(Observer o)  主题对象注册观察者
protected void clearChanged()  指示对象不再改变,或者它已对其所有的观察者通知了最近的改变,所有hasChange方法返回true
int countObservers() 返回观察者的数目
void deleteObserver(Observer o) 删除指定观察者
void deleteObservers() 删除所有观察者
boolean hasChanged() 测试对象是否改变
void notifyObservers() 如果hasChanegd方法指示对象已改变,则通知所有观察者,然后调用clearChanged方法
void notifyObservers(Object arg) 与上一方法不同之处在于,通知观察者时,传入参数
protected void setChanged() 标记主题发生改变

Observable类中实现了注册,删除和通知观察者的方法,其余的函数在下面会详细介绍。

   2、观察者如何来实现观察者接口 

    通过实现Observer接口来实现观察者类

public class CurrentConditionDisplay implements Observer {

	
	@Override
	public void update(Observable o, Object arg) {

	}
update函数中的参数Observable让观察者知道是哪个主题通知它的,观察者可以利用该变量来实现pull方式更新。
如果想通过推PUSH的方式来更新观察者,在主题中会调用notifyObservers(arg)方法,该方法调用update时传入了arg参数来更新观察者,所以可以看到参数Object可以为空的。

   3、主题如何通知观察者

        (1)先调用setChanged()方法,标记状态已发生改变的事实。

        (2)然后调用两中notifyObservers()方法中的一种:notifyObservers(),notifyObservers(arg)。该函数执行完后其内部会调用clearChanged()的。

   我们来看一下通过Java内置的观察者模式的Pull方式更新观察者的实现代码

主题类

import java.util.Observable;

public class WeatherData extends Observable {
	
	private float temperature;
	private float humidity;
	private float pressure;
	
	public void setMeasure(float temp,float humi,float press){
		this.temperature=temp;
		this.humidity=humi;
		this.pressure=press;
		this.setChanged();
		notifyObservers();
	}
	
	public float getTemperature(){
		return temperature;
	}
	
	public float getHumidity(){
		return humidity;
	}
	
	public float getPressure(){
		return pressure;
	}
	
}
观察者

import java.util.Observable;
import java.util.Observer;

public class CurrentConditionDisplay implements Observer {

	private Observable observale;
	private float temperature;
	private float humidity;
	private float pressure;
	
	@Override
	public void update(Observable o, Object arg) {
		this.observale=o;
		temperature=((WeatherData)observale).getTemperature();
		humidity=((WeatherData)observale).getHumidity();
		pressure=((WeatherData)observale).getPressure();
		System.out.println("temperature:"+temperature+"humidity:"+humidity+"pressure:"+pressure);
	}

}
测试程序

public class WeatherStation {

	public static void main(String arg[]){
		
		WeatherData weatherData=new WeatherData();
		CurrentConditionDisplay currentConditionDisplay=new CurrentConditionDisplay();
		weatherData.addObserver(currentConditionDisplay);
		weatherData.setMeasure(100, 20, 50);
	}
}

输出结果

temperature:100.0humidity:20.0pressure:50.0


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值