设计模式-观察者模式

转载请注明本文出自1124117571的博客(www.1124117571.iteye.com),谢谢支持!

观察者模式(Observer)行为型模式

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

 

OO原则:为了交互对象之间的松耦合设计而努力

当两个对象之间松耦合,它们依然可以交互,但是不太清楚彼此的细节。观察者模式提供了一种对象设计,让主题观察者之间松耦合。具体过程,假如我们有个新的具体类需要当观察者,我们不需要为了兼容新类型而修改主题的代码,所有要做的就是在新的类里实现此观察者接口,然后注册为观察者即可。主题不在乎别的,它只会发送通知给所有实现了观察者接口的对象。

 

下面拿气象站的例子来说明观察者模式

 

下面是气象站例子的UML图

                               WeatherStation的UML图

 

 下面是UML图中各个成分的具体代码:

 

气象站的布告板:

 

/*
 * 气象站的布告板
 */
public interface Subject {
	public void registerObserver(Observer o);	// 用来注册观察者
	public void removeObserver(Observer o);		// 用来移除观察者
	public void notifyObservers();	// 当主题状态改变时,这个方法会被调用以通知所有的观察者
}

 

 

观察者接口:

 

/*
 * 所有的气象组件都实现此观察者接口
 * 所有的观察者都必须实现update方法,以实现观察者接口
 */
public interface Observer {
	public void update(float temp,float humidity,float pressure);
}

 

 

当布告板需要显示时,调用此方法

 

/*
 * 当布告板需要显示时,调用此方法
 */
public interface DisplayElement {
	public void display();
}

 

 

WeatherData对象(追踪来自气象站的数据,并更新布告板)

 

/*
 * WeatherData对象(追踪来自气象站的数据,并更新布告板)
 */
public class WeatherData implements Subject {
	private ArrayList<Observer> observers;
	private float temperature;	// 温度值
	private float humidity;		// 湿度值
	private float pressure;		// 气压值
	
	public WeatherData(){
		observers = new ArrayList<Observer>();
	}
	
	// =====================Subject接口的实现================================
	public void registerObserver(Observer o){	// 当注册观察者时,我们只需要把它加到ArrayList的后面即可
		observers.add(o);
	}
	
	public void removeObserver(Observer o){
		int i = observers.indexOf(o);
		if(i > 0){	// 说明ArrayList中存在该观察者
			observers.remove(i);	
		}
	}
	
	public void notifyObservers(){
		for(int i = 0;i < observers.size();i++){
			Observer observer = (Observer)observers.get(i);
			// 通过观察者的接口向观察者发送通知
			observer.update(temperature, humidity, pressure);
		}
	}
	// =================================================================
	
	// 当从气象站得到更新观测值时,我们通知观察者
	public void messurementsChanges(){
		notifyObservers();
	}
	
	public void setMeasurements(float temperature,float humidity,float pressure){
		this.temperature = temperature;
		this.humidity = humidity;
		this.pressure = pressure;
		messurementsChanges();
	}
	
	// WeatherData的其他方法
}

 

 

建立布告板

 

/*
 * 此布告板实现了Observer接口,所以可以从WeatherData对象中获得改变
 * 规定了所有的布告板都必须实现DisplayElement接口
 */
public class CurrentConditionDisplay implements Observer, DisplayElement {

	private float temperature;
	private float humidity;
	private Subject weatherData;

	public CurrentConditionDisplay(Subject weatherData) {
		this.weatherData = weatherData; // 需要weatherData对象作为注册用
		weatherData.registerObserver(this);
	}

	// 把最近的温度和湿度显示出来
	@Override
	public void display() {
		System.out.println("Current conditions:" + temperature + "F degrees and " + humidity + "% humidity");
	}

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

 

 

 

测试程序WeatherStation

/**
 * 测试程序WeatherStation
 * @author asus
 *
 */
public class WeatherStation {
	public static void main(String[] args){
		WeatherData weatherData = new WeatherData();
		CurrentConditionDisplay currentDisplay = new CurrentConditionDisplay(weatherData);
		// 模拟新的气象测量
		weatherData.setMeasurements(80, 65, 30.4f);
		weatherData.setMeasurements(82, 70, 29.2f);
		weatherData.setMeasurements(78, 90, 29.2f);
	}
}

 

测试结果



 

 

以上都是通过自己的努力从无到有地完成了观察者模式,但是Java API有内置的观察者模式。

java.util包内包含最基本的Observer接口和Observable类

Observable类追踪所有观察者并通知他们



 

 

 Java内置的观察者模式如何运作:

如何把对象变成观察者?

答:实现观察者接口(java.util.Observer),然后调用任何Observer对象的addObserver方法,不想再当观察者时,调用deleteObserver()方法就可以了。

 

观察者如何送出通知?

答:1.首先需要李勇扩展java.util.Observer接口产生“可观察者”类。

   2.先调用setChanged()方法,标记状态已经改变的事实。

   3.然后调用两种notifyObservers()方法中的一个。

  

setChanged()方法的用处?

答:setChanged()方法用来标记状态已经改变的事实,好让notifyObservers()知道当它被调用时应该更新观察者,如果调用notifyObservers()之前没有先调用setChanged(),观察者就不会被通知。

 

 

Obserser类内部伪代码

 

setChanged(){
	changed = true;	// setChanged()方法把changed标志设为true
}

// notifyObservers只会在changed标为true时通知观察者
notifyObservers(Object args){
	if(changed()){
		for every Observer on the list{
			can udpate(this,args);
		}
		changed = false;	// 在通知观察者之后,把changed标志设置为false
	}

 

 

下面就进行改造,改造成使用Java内置的观察者模式

 

1.把WeatherData改成使用java.util.Observable

 

public class WeatherData extends Observable{
	private float temperature;
	private float humidity;
	private float pressure;
	
	public WeatherData(){}
	
	public void measurementsChanged(){
		setChanged();	// 在调用notifyObservers()之前,要先调用setChanged()来指示状态已经改变
		notifyObservers();	// 没有调用notifyObservers()传送数据对象,我们采用的做法是"拉"
	}
	
	//=======================================================
	// 观察者会利用下面这些方法取得WeatherData对象的状态
	public void setMeasurements(float temperature,float humidity,float pressure){
		this.temperature = temperature;
		this.humidity = humidity;
		this.pressure = pressure;
		measurementsChanged();
	}
	
	public float getTemperature(){
		return temperature;
	}
	
	public float getHumidity(){
		return humidity;
	}
	
	public float getPressure(){
		return pressure;
	}
	//=======================================================

	// WeatherData的其他方法
}

 

注意:

继承Observable表明该类是发送者(消息提供者)。

继承Observer表明该类是接收者(观察者)。

 

 

2.重做CurrentConditionDisplay

public class CurrentConditionDisplay implements Observer, DisplayElement {

	Observable observable;
	private float temperature;
	private float humidity;

	public CurrentConditionDisplay(Observable observable) {
		this.observable = observable;
		observable.addObserver(this);
	}

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

	@Override
	public void update(Observable obs, Object arg) {
		if (obs instanceof WeatherData) {
			WeatherData weatherData = (WeatherData) obs;
			this.temperature = weatherData.getTemperature();
			this.humidity = weatherData.getHumidity();
			display();
		}
	}

}

 

 

测试结果:



 

 

Java内置的观察者模式的缺点:

1.Observable是一个类,从而限制了Observable的潜力,因为没有Observable接口,我们无法建立自己的实现和Java内置的Observer API配套使用。

2.违反了OO设计原则:多用组合,少用继承,因此除非你继承自Observable,否则将无法创建Observable实例并组合到我的对象中。

 

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值