2008-01-24

设计模式入门学习之观察者模式(2)

关键字: 设计模式

java API提供了内置的观察者模式,java.util包内包含最基本的Observer接口和Observable类,这和我们在上一篇介绍观察者模式中写的Subject接口和Observer很相似,但使用内置的更方便,因为许多功能已经事先准备好了,你甚至可以使用推(push)或拉(pull)的方式传送数据.
那么我们来看一下java内置的观察者模式如何运作:
1.如何把对象变成观察者
         如同以前一样,实现观察者接口java.util.Observer,然后调用任何Observable对象的addObserver()方法,删除观察者可以用deleteObserver()方法
2.可观察者要如何送出通知...
       a.扩展java.util.Observable接口产生"可观察者"类
       b.先调用setChanged()方法,标记状态已经改变的事实,好让notifyObservers()知道当它被调用是应该更新观察者,我们来看下Observer内部,以了解这一 切:

 

setChanged(){
	changed=true;	//把change设为true
}
//当通知时,此版本可以传送任何的数据对象给每一个观察者
notifyObservers(Object arg){
                //notifyObservers只会在change为true时才会通知观察者
	if(change){
		for every observer on the list{
		             call update(this,arg)
		}
		//通知观察者之后把change标志设为false
		change=false;
	}
}
notifyObservers(){
	notifyObservers(null);
}
//...

c.然后调用上面2种notifyObservers()方法中的一个
3.观察者如何接收通知? 一样,观察者实现了更新的方法,但是签名不太一样

/**
* 参数1:主题本身,好让观察者知道是哪个主题通知它
* 参数2:传入notifyObservers()的数据对象,没有则为null
/
update(Observer o,Object org)

 

如果你想推(push)数据给观察者,你可以把数据当作数据对象传送给notifyObservers(arg)方法
但是如何拉(pull)数据呢,我们来改造气象站:

 

//---------------把WeatherDate改成使用java.util.Observable
public class WeatherData extends Observable {
	//继承Observable,不需要追踪观察者了,也不要管理注册和删除,让超类代劳
	private float temperature;
	private float humidity;
	private float pressure;
	
	public WeatherData() { }
	
	public void measurementsChanged() {
		//先调用setChanged来指示状态已经改变
		setChanged();
		//注意:我们没有传送数据对象,这表示我们采用的做法是"拉(pull)"
		notifyObservers();
	}
	
	public void setMeasurements(float temperature, float humidity, float pressure) {
		this.temperature = temperature;
		this.humidity = humidity;
		this.pressure = pressure;
		measurementsChanged();
	}
	//使用"拉"方法时,取得WeatherData对象的状态
	public float getTemperature() {
		return temperature;
	}
	
	public float getHumidity() {
		return humidity;
	}
	
	public float getPressure() {
		return pressure;
	}
}
//---------重做CurrentConditionsDisplay
public class CurrentConditionsDisplay implements Observer, DisplayElement {
	Observable observable;
	private float temperature;
	private float humidity;
	//构造器需要observable作为参数,并将CurrentConditionsDisplay对象登记为观察者
	public CurrentConditionsDisplay(Observable observable) {
		this.observable = observable;
		observable.addObserver(this);
	}
	//这里也是要改变的地方,先确定观察者属于WeatherData类型,再调用get方法获取温度和湿度并显示
	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");
	}
}

 

 

如果你运行了这2个例子,你会发现,文字输出的次序不一样,不要依赖于观察者被通知的次序
你可能注意到了,java.util.Observable是一个类而不是一个接口,所以你必须设计一个类继承它,如果一个类想同时具有Observable类和另一个超类的行为,就会陷入两难,比较java不支持多重继承,这限制了Observable的复用能力,仔细看Observable API,setChange()方法是protected,被保护起来了,这就意味着:除非你继承Observable,否则你无法创建Observable示例并组合到你自己的对象中,这个设计违反了第二个设计原则:多用组合,少用继承.
不管你用哪种方法,反正你已经熟悉观察者模式了,不是吗?

评论
blank 2008-01-31

改过来了,谢谢!
fulianglove 2008-01-31
:D全是我
fulianglove 2008-01-31
arg
fulianglove 2008-01-31
org
fulianglove 2008-01-31
应该是call update(this,arg)
fulianglove 2008-01-30
非常好!!!!
发表评论

您还没有登录,请登录后发表评论

blank
搜索本博客
我的相册
5c2c51d9-1a15-3713-8084-e1742c808801-thumb
P1080256
共 30 张
存档
最新评论