2. 观察者模式(Observer pattern)

本文介绍观察者模式的应用,通过一个气象站的例子展示了如何利用该模式实现主题与观察者之间的松耦合,使得当主题状态发生变化时,所有依赖于它的观察者都能自动接收到更新。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Referenced by Head First Design Pattern

观察者模式提供了一种对象设计,让主题和观察者之间松耦合

对于实现气象站的功能,我们有一个WeatherData对象负责追踪目前的天气状况,我们的目的是希望建立几个布告板,当天气变化时候更新它们。

对于WeatherData对象的说明:


这个对象提供了get方法来读取天气状况,同时气象测试时,会调用measurementsChanged()方法

需要注意的是,我们有多个布告板需要更新,那么应该怎么做呢?

最直接的做法,在measurementsChanged()中直接更新布告板:

public void measurementsChanged() {
		float temp = getTemperature();
		float humidity = getHumidity();
		float pressure = getPressure();
		currentConditionsDisplay.update(temp, humidity, pressure);
		statisticsDisplay.update(temp, humidity, pressure);
		forecastDisplay.update(temp, humidity, pressure);//分别更新每个布告板
	}

但是我们犯了很明显的错误:

1.针对具体实现编程,而非针对接口。

2.对于每个新的布告板,我们都得修改代码。

3.我们无法再运行时动态的添加(或删除)布告板

4.我们尚未封装改变的部分。


那么,什么是观察者模式呢


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

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

松耦合的设计之所以能让对象建立有弹性的OO系统,能够应对变化,是因为对象之间的互相依赖降到了最低。

观察者模式类图:



主题接口:

public interface Subject {
	public void registerObserver(Observer o);//添加观察者
	public void removeObserver(Observer o);//删除观察者
	public void notifyObservers();//当主题改变时,调用这个方法来通知观察者
}

观察者接口:

public interface Observer {
	public void update(float tmp, float humidity, float pressure);//观察者需要实现这个方法来接收通知
}

WeatherData类实现具体的主题:

public class WeatherData implements Subject{
	private ArrayList observers;
	private float temperature;
	private float humidity;
	private float pressure;
	public WeatherData() {
		observers = new ArrayList();
	}
	@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);
		}
	}
	@Override
	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 setMeasurements(float temperature, float humidity, float pressure) {
		this.temperature = temperature;
		this.humidity = humidity;
		this.pressure = pressure;
		measurementsChanged();
	}
}

定义一个布告板对象来实现具体的观察者:

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 tmp, float humidity, float pressure) {
		this.temperature = tmp;
		this.humidity = humidity;
		display();
	}
	@Override
	public void display() {
		System.out.println("Current conditions: "+temperature+"F degrees and "+humidity+"% humidity");
	}
}

测试时,就可以使用:

WeatherData weatherData = new WeatherData();
		CurrentConditionsDisplay currentDisplay = new CurrentConditionsDisplay(weatherData);//同时构造函数中将布告板对象添加到观察者列表中去
		//还可以建立其他的公告板
		weatherData.setMeasurements(80, 65, 30.4f);
		weatherData.setMeasurements(82, 70, 29.2f);
		weatherData.setMeasurements(78, 90, 29.2f);

在JDK中,有许多地方用到了观察者模式,比如button的事件监听等。

JButton button = new JButton("Should I do it?");
		button.addActionListener(new AngelListener());
		button.addActionListener(new DevilListener());//建立了2个
		class AngelListener implements ActionListener{
			@Override
			public void actionPerformed(ActionEvent e){}//当按下按钮时被调用
		}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值