Java设计模式学习笔记——观察者模式

116 阅读3分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路

首先来看看观察者模式的概念

在对象之间定义一对多的依赖,这样一来,当一个对象改变状态,依赖它的对象都会收到通知,并自动更新

( 例子参考自《HeadFirst设计模式》)

假设现在有一个气象站,多个公告板,当气象站数据发生变化时,这些公告板的显示内容也要进行相应的更新

先来开一个错误的示范:

//更新方法
public void measurementsChanged(){
	//获取温度、湿度、气压值
	float temp = getTemperature();
	float humidity = getHumidity();
	float pressure = getPressure();
	//更新公告板
	currentConditionsDisplay.update(temp, humidity, pressure);
	statisticsDisplay.update(temp, humidity, pressure);
}

这样的代码是针对具体实现编程,而不是针对接口编程,如果我们要加新的公告板,就要修改代码,而且我们无法在运行的时候动态增加或删除公告板。所以,我们得把需要动态改变的地方封装起来

在观察者模式中,存在主题(Subject)和观察者(Observer),观察者可以注册进相应的主题,也可以从主题中将自己移出来,主题对象管理的数据会通知所有注册过的观察者,一旦观察者将自己移除,那么主题就不再通知这个观察者

在这个例子中,气象站就相当于主题,各个公告板就相当于观察者,一个主题可以被多个观察者观察

我们先来建立所需要的接口

//主题接口
public interface Subject {
	
	//注册观察者
	public void registerObserver(Observer observer);
	
	//移除观察者
	public void removeObserver(Observer observer);
	
	//通知观察者
	public void notifyObserver();
	
}
//观察者接口
public interface Observer {
	public void update(float temp, float humidity, float pressure);
}
//公告板接口
public interface DisplayElement {
	public void display();	//目前公告板只有一个显示数据的方法,后续你也可以添加更多的方法
}

接口建立完毕,我们来实现气象站

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 observer) {
		observers.add(observer);
	}

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

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

}

再建立两个公告板

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

	@Override
	public void display() {
		System.out.println("这是 statistics display");
		System.out.println("现在的温度是:" + temperature);
		System.out.println("现在的湿度是:" + humidity);
		System.out.println("现在的大气压是:" + pressure);
	}

	@Override
	public void update(float temperature, float humidity, float pressure) {
		this.temperature = temperature;
		this.humidity = humidity;
		this.pressure = pressure;
		display();
	}
}
public class CurrentConditionsDisplay implements Observer, DisplayElement{
	
	private float temperature;
	
	private float humidity;
	
	private float pressure;
	
	private Subject weatherData;
	
	public CurrentConditionsDisplay(Subject subject) {
		this.weatherData = subject;
		weatherData.registerObserver(this);
	}

	@Override
	public void display() {
		System.out.println("这是 weather station");
		System.out.println("现在的温度是:" + temperature);
		System.out.println("现在的湿度是:" + humidity);
		System.out.println("现在的大气压是:" + pressure);
	}

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

最后启动气象站

public class WeatherStation {
	public static void main(String[] args) {
		WeatherData weatherData = new WeatherData();
		CurrentConditionsDisplay conditionsDisplay = new CurrentConditionsDisplay(weatherData);
		StatisticsDisplay statisticsDisplay = new StatisticsDisplay(weatherData);
		weatherData.setMeasurements(80.0f, 65.0f, 30.4f);
		weatherData.setMeasurements(70.0f, 55.0f, 20.4f);
	}
}

20201013175654915.png

当我们需要动态增加或删除公告板时,只要调用weatherData的registerObserver()方法和removeObserver()方法就可以达到动态更新的效果了