23种设计模式之-----观察者模式(Observer Pattern)

进入正题之前,我给对于设计模式来说还是新手的同学推荐一本学习设计模式的书,这本书叫做《Head First设计模式》,如果可能的话,看英文原版能让你更加贴近于作者的思想。

进入正题,这次我学习的是观察者模式(Observer Pattern),在java语言中用得最多的设计模式之一。

观察者模式,又叫发布-订阅模式,具体的定义是:定义了对象之间一对多的依赖,当一个对象的状态改变时,它的所有依赖者都将受到通知并进行相应的更新。

类图:


根据类图我们不难看出观察者模式的结构:

Subject:主题接口,用于注册观察者或移除观察者。

Observer:观察者接口,所有具体的观察者都必须实现这个接口,一个主题可以有多个观察者。该接口只有一个update方法,当主题状态改变时,该方法被调用。

ConcreteSubject:具体主题,实现Subject接口,并且实现了notifyObserver方法,用于改变状态时通知Observer。

ConcreteObsever:具体观察者,实现Observer接口,具体观察者必须注册具体主题,便于接收更新,具体观察者可以是多个。


在学习观察者模式时,《Head First设计模式》一书中引入了一个栗子:

当天气发生变化时(温度,湿度,气压),通知各个气象站,修改气象板相应的数据。

观察者接口:

public interface Observer {
	public void update(float temp, float humidity, float pressure);
}


主题接口:
public interface Subject {
	//添加观察者
	public void register(Observer observer);
	//移除观察者
	public void remove(Observer observer);
	//当主题发生变化时,通知观察者
	public void notifyObserver();
}

天气数据(具体主题):
public class WeatherData implements Subject {
	//观察者可能是多个,所以应该是一个集合
	private List<Observer> observers;
	private float temperature;
	private float humidity;
	private float pressure;

	public WeatherData() {
		observers = new ArrayList<>();
	}

	@Override
	public void register(Observer observer) {
		observers.add(observer);
	}

	@Override
	public void remove(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 = 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();
	}
}

气象站1:

public class WeatherStationOne implements Observer {
	private float temperature;
	private float humidity;
	private Subject weatherDate;

	public WeatherStationOne(Subject weatherDate) {
		this.weatherDate = weatherDate;
		weatherDate.register(this);
	}

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

	public void display(){
		System.out.println("WeatherStationOne   temperature=" + temperature + ";humidity" + humidity);
	}
}

气象站2:
public class WeatherStationTwo implements Observer{
	private float temperature;
	private float pressure;
	private Subject weatherDate;

	public WeatherStationTwo(Subject weatherDate) {
		this.weatherDate = weatherDate;
		weatherDate.register(this);
	}

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

	public void display(){
		System.out.println("WeatherStationTwo   temperature=" + temperature + ";pressure" + pressure);
	}

}

测试类:
public class Client {
	public static void main(String[] args) {
		WeatherData weatherData = new WeatherData();
		WeatherStationOne weatherStationOne= new WeatherStationOne(weatherData);
		WeatherStationTwo weatherStationTwo = new WeatherStationTwo(weatherData);
		weatherData.setMeasurements(33.5f,34.2f,35.7f);
		weatherData.setMeasurements(33.12f, 66.66f, 99.99f);
		weatherData.setMeasurements(44.44f, 55.55f, 66.696f);
	}
}

测试结果:


以上即做到了,当数据发生变化时,通知到具体的各个气象站。



以上的观察者是我们自己来实现的,事实上,在JDK中已经内置了对观察者模式的支持。

修改WeatherData类为WeatherDataForJDK:此处需要继承jdk内置的Obserable类

public class WeatherDataForJDK extends Observable{
	private float temperature;
	private float humidity;
	private float pressure;

	public WeatherDataForJDK() {
	}
	public void measurementsChanged(){
		setChanged();
		notifyObservers();
	}

	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 void setTemperature(float temperature) {
		this.temperature = temperature;
	}

	public float getHumidity() {
		return humidity;
	}

	public void setHumidity(float humidity) {
		this.humidity = humidity;
	}

	public float getPressure() {
		return pressure;
	}

	public void setPressure(float pressure) {
		this.pressure = pressure;
	}
}

修改WeatherStationOne类为WeatherStationOneForJDK: 此处需要实现JDK内置的Observer接:

public class WeatherStationOneForJDK implements Observer{
	private Observable observable;
	private float temperature;
	private float humidity;

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

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

	public void display(){
		System.out.println("WeatherStationOne   temperature=" + temperature + ";humidity" + humidity);
	}
}

同理,修改WeatherStationTwo为WeatherStationTwoForJDK:
public class WeatherDataTwoForJDK implements Observer {
	private Observable observable;
	private float temperature;
	private float pressure;

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

	@Override
	public void update(Observable o, Object arg) {
		if (o instanceof WeatherDataForJDK){
			WeatherDataForJDK weatherDataForJDK = (WeatherDataForJDK) o;
			this.temperature = weatherDataForJDK.getTemperature();
			this.pressure = weatherDataForJDK.getPressure();
			display();
		}
	}

	public void display(){
		System.out.println("WeatherStationTwo   temperature=" + temperature + ";pressure" + pressure);
	}
}


测试类:
public class Client {
	public static void main(String[] args) {
		WeatherDataForJDK weatherDataForJDK = new WeatherDataForJDK();
		WeatherStationOneForJDK weatherStationOne= new WeatherStationOneForJDK(weatherDataForJDK);
		WeatherDataTwoForJDK weatherStationTwo = new WeatherDataTwoForJDK(weatherDataForJDK);
		weatherDataForJDK.setMeasurements(33.5f,34.2f,35.7f);
		weatherDataForJDK.setMeasurements(33.12f, 66.66f, 99.99f);
		weatherDataForJDK.setMeasurements(44.44f, 55.55f, 66.696f);
	}
}

测试结果:



各位一定要亲自动手敲一遍哦。着实很神奇呢。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值