天天看点

设计模式:观察者模式如何实现发布订阅

作者:日拱一卒程序猿

一、定义

观察者模式也叫发布订阅模式。

在对象之间定义一个一对多的依赖,当一个对象状态发生改变的时候,所有依赖的对象都会自动收到通知。

被依赖的对象是Subject(主题,也叫被观察者),依赖的对象是Observer(观察者)。

二、原理类图

设计模式:观察者模式如何实现发布订阅

(1)抽象主题(Subject):

它把所有观察者对象的引用保存到一个聚集里,每个主题都可以有任何数量的观察者。抽象主题提供一个接口,可以增加和删除观察者对象。

(2)具体主题(Concrete Subject):

将有关状态存入具体观察者对象;在具体主题内部状态改变时,给所有登记过的观察者发出通知。

(3)抽象观察者(Observer):

为所有的具体观察者定义一个接口,在得到主题通知时更新自己。

(4)具体观察者(Concrete Observer):

实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题状态协调。

三、案例

1、需求

天气预报项目需求,具体要求如下:

(1)气象站可以将每天测量到的温度,湿度,气压等等以公告的形式发布出去(比如 发布到自己的网站或第三方)。

(2)需要设计开放型API,便于其他第三方也能接入气象站获取数据。

(3)提供温度、气压和湿度的接口

(4) 测量数据更新时,要能实时的通知给第三方

设计模式:观察者模式如何实现发布订阅

2、代码实现

//接口, 让具体主题类WeatherData 来实现 
public interface Subject {

    public void registerObserver(Observer o);

    public void removeObserver(Observer o);

    public void notifyObservers();

}

//观察者接口,有观察者来实现
public interface Observer {

	public void update(float temperature, float pressure, float humidity);

}

/**
 * 类是核心
 * 1. 包含最新的天气情况信息 
 * 2. 含有 观察者集合,使用ArrayList管理
 * 3. 当数据有更新时,就主动通知所有的(接入方)就看到最新的信息
 * @author Administrator
 *
 */
public class WeatherData implements Subject {
	private float temperatrue;
	private float pressure;
	private float humidity;
	// 观察者集合
	private ArrayList<Observer> observers;

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

	public float getTemperature() {
		return temperatrue;
	}

	public float getPressure() {
		return pressure;
	}

	public float getHumidity() {
		return humidity;
	}

	// 当数据有更新时,就调用 setData
	public void setData(float temperature, float pressure, float humidity) {
		this.temperatrue = temperature;
		this.pressure = pressure;
		this.humidity = humidity;
		// 调用notifyObservers, 将最新的信息 推送给观察者
		notifyObservers();
	}

	// 注册一个观察者
	@Override
	public void registerObserver(Observer o) {
		observers.add(o);
	}

	// 移除一个观察者
	@Override
	public void removeObserver(Observer o) {
		if (observers.contains(o)) {
			observers.remove(o);
		}
	}

	// 遍历所有的观察者,并通知
	@Override
	public void notifyObservers() {
		for (int i = 0; i < observers.size(); i++) {
			observers.get(i).update(this.temperatrue, this.pressure, this.humidity);
		}
	}
}

public class CurrentConditions implements Observer {

	// 温度,气压,湿度
	private float temperature;
	private float pressure;
	private float humidity;

	// 更新 天气情况,是由 WeatherData 来调用,我使用推送模式
	public void update(float temperature, float pressure, float humidity) {
		this.temperature = temperature;
		this.pressure = pressure;
		this.humidity = humidity;
		display();
	}

	// 显示
	public void display() {
		System.out.println("***Today mTemperature: " + temperature + "***");
		System.out.println("***Today mPressure: " + pressure + "***");
		System.out.println("***Today mHumidity: " + humidity + "***");
	}
}

public class BaiduSite implements Observer {

	// 温度,气压,湿度
	private float temperature;
	private float pressure;
	private float humidity;

	// 更新 天气情况,是由 WeatherData 来调用,我使用推送模式
	public void update(float temperature, float pressure, float humidity) {
		this.temperature = temperature;
		this.pressure = pressure;
		this.humidity = humidity;
		display();
	}

	// 显示
	public void display() {
		System.out.println("===百度网站====");
		System.out.println("***百度网站 气温 : " + temperature + "***");
		System.out.println("***百度网站 气压: " + pressure + "***");
		System.out.println("***百度网站 湿度: " + humidity + "***");
	}

}

public class Client {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		// 创建一个WeatherData
		WeatherData weatherData = new WeatherData();

		// 创建观察者
		CurrentConditions currentConditions = new CurrentConditions();
		BaiduSite baiduSite = new BaiduSite();

		// 注册到weatherData
		weatherData.registerObserver(currentConditions);
		weatherData.registerObserver(baiduSite);

		// 测试
		System.out.println("通知各个注册的观察者, 看看信息");
		weatherData.setData(10f, 100f, 30.3f);

		weatherData.removeObserver(currentConditions);
		// 测试
		System.out.println();
		System.out.println("通知各个注册的观察者, 看看信息");
		weatherData.setData(10f, 100f, 30.3f);
	}

}

           

4、好处

(1) 使用观察者模式设计,就可以用集合的方式来管理用户(Observer),包括注册,移除 和通知。

(2)这样,我们增加观察者(这里可以理解成一个新的公告板),就不需要去修改核 心类WeatherData不会修改代码,遵守了ocp原则。

四、应用

Jdk的Observable类和Observer接口就使用了观察者模式

(1)Observable 的作用和地位等价于 我们前面讲过 Subject

(2)Observable 是类,不是接口,类中已经实现了核心的方法,即管理Observer的方法add()、delete()、notify()

(3)Observer 的作用和地位等同于我们前面讲过的 Observer,定义了抽象方法 update()

(4)Observable 和 Observer 的使用方法和前面讲过的一样,只是Observable 是类,通过继承来管理观察者,实现观察者模式。

关注私信可获取更多详细课程资料

继续阅读