【设计模式】HeadFirst设计模式(二):观察者(Observer)模式

一、观察者模式定义

在观察者模式中,一个被观察者管理所有依赖于它的观察者对象,它定义了一个一对多的依赖关系,这样一来,当一个对象改变状态时,它的所有依赖者都会受到通知并自动更新。

主题(被观察者)通过一个共同的接口来更新观察者,观察者依赖于此主题。

二、观察者模式例子——气象监测系统

描述:

气象监测系统分为三个部分:气象站(获取实际气象数据的物理装置)、WeatherData对象(追踪来自气象站的数据,并更新布告板)和布告板(显示目前天气状况给用户看)

布告板分为三个:目前状况(显示WeatherData当前观测值)、气象统计(显示最小、平均和最大的观测值)、天气预报(根据气压计显示天气预报)

目标:

当WeatherData对象改变的时候,自动更新三个布告板

实现:

首先,我们看一下WeatherData类的源文件:

getTemperature()、getHumidity()、getPressure()三个方法分别为获得温度、湿度、气压

measurementsChanged():一旦测量更新,此方法会被调用(不需要在乎如何被调用)

然后,我们在measurementsChanged()方法里边添加代码:

<span style="font-family:SimSun;font-size:18px;">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);
	}</span>

我们看到,上边的三个方法像是一个统一的接口,并且是改变的,是针对具体实现编程的,这会导致以后在增加或删除布告板时必须修改程序

在这里,引入一个概念——松耦合:当两个对象之间松耦合,它们依然可以交互,但是不太清楚彼此的细节。

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

主题只需要知道观察者实现了某个接口(Observer接口),主题不需要知道观察者的具体类是谁,做了什么或其他任何细节

可以画出来类图:

一个主题可以拥有很多的观察者(它们之间是组合的关系,下边会介绍),主题里边有以下方法:

registerObserver():给主题注册观察者

removeObserver():移除主题的观察者

notifyObserver():通知观察者

观察者有一个方法:

update():根据通知进行更新

下边,把气象站的类图设计出来并对其具体实现:

Subject接口:具有注册、移除、通知观察者方法

WeatherData类,继承Subject接口:

(1) 属性:观察者List、温度、湿度、气压

(2) 方法:注册、移除、通知观察者,获得温度、湿度、气压和当状态发生改变的时候通知观察者

Observer接口:具有更新方法

DisplayMent接口:为布告板建立的同意接口,布告板只需要实现display方法

CurrentConditionsDisplay类:根据WeatherData对象显示当前观测值

StatisticsDisplay类:显示最小、平均和最大的观测值

下边用代码进行具体的实现:

Subject接口:

<span style="font-family:SimSun;font-size:18px;">public interface Subject {
	void registerObserver(Observer o);

	void removeObserver(Observer o);

	void notifyObservers();
}
</span>

WeatherData类:

<span style="font-family:SimSun;font-size:18px;">public class WeatherData implements Subject {
	//放入观察者
	private ArrayList<Observer> observers;
	private float temperature;
	private float humidity;
	private float pressure;

	public WeatherData() {
		observers = new ArrayList<Observer>();
	}
	public void registerObserver(Observer o) {
		observers.add(o);
	}
	public void removeObserver(Observer o) {
		int i = observers.indexOf(o);
		if (i >= 0) {
			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 measurementsChanged() {
		notifyObservers();
	}
	//更新weather data数据
	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;
	}
}</span>

Observer接口:

<span style="font-family:SimSun;font-size:18px;">public interface Observer {
	void update(float temp,float humidity, float pressure);
}</span>

DisplayMent接口:

<span style="font-family:SimSun;font-size:18px;">public interface DisplayElement {
	void display();
}</span>

CurrentConditionsDisplay类:

<span style="font-family:SimSun;font-size:18px;">public class CurrentConditionsDisplay implements Observer, DisplayElement {
	private float temperature;
	private float humidity;
	//初始化的时候就注册成为观察者
	public CurrentConditionsDisplay(Subject weatherData) {
		weatherData.registerObserver(this);
	}

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

	public void display() {
		System.out.println("Current conditions: " + temperature
				+ "F degrees and " + humidity + "% humidity");
	}
}</span>

StatisticsDisplay类:显示最小、平均和最大的观测值

<span style="font-family:SimSun;font-size:18px;">public class StatisticsDisplay implements Observer, DisplayElement {
	private float maxTemp = 0.0f;
	private float minTemp = 200;
	private float tempSum = 0.0f;
	private int numReadings;
	//初始化的时候注册成为观察者
	public StatisticsDisplay(WeatherData weatherData) {
		weatherData.registerObserver(this);
	}

	public void update(float temp, float humidity, float pressure) {
		tempSum += temp;
		numReadings++;

		if (temp > maxTemp) {
			maxTemp = temp;
		}
		if (temp < minTemp) {
			minTemp = temp;
		}
		display();
	}

	public void display() {
		System.out.println("Avg/Max/Min temperature = "
				+ (tempSum / numReadings) + "/" + maxTemp + "/" + minTemp);
	}
}</span>

下边写一个main函数来验证一下:

<span style="font-family:SimSun;font-size:18px;">public class WeatherStation {

	public static void main(String[] args) {
		WeatherData weatherData = new WeatherData();
		CurrentConditionsDisplay cu = new CurrentConditionsDisplay(weatherData);
		StatisticsDisplay st = new StatisticsDisplay(weatherData);

		weatherData.setMeasurements(80, 65, 30.4f);
		System.out.println("======================");
		weatherData.setMeasurements(82, 70, 29.2f);
		System.out.println("======================");
		weatherData.setMeasurements(78, 90, 29.2f);
		System.out.println("======================");
		//下边把StatisticsDisplay这个观察者移除了
		weatherData.removeObserver(st);
		weatherData.setMeasurements(90, 70, 35.5f);
	}
}</span>

输出:

<span style="font-family:SimSun;font-size:18px;">Current conditions: 80.0F degrees and 65.0% humidity
Avg/Max/Min temperature = 80.0/80.0/80.0
======================
Current conditions: 82.0F degrees and 70.0% humidity
Avg/Max/Min temperature = 81.0/82.0/80.0
======================
Current conditions: 78.0F degrees and 90.0% humidity
Avg/Max/Min temperature = 80.0/82.0/78.0
======================
Current conditions: 90.0F degrees and 70.0% humidity</span>
时间: 2024-10-09 20:22:27

【设计模式】HeadFirst设计模式(二):观察者(Observer)模式的相关文章

设计模式(十二)外观模式(结构型)

概述 外观模式,我们通过外观的包装,使应用程序只能看到外观对象,而不会看到具体的细节对象,这样无疑会降低应用程序的复杂度,并且提高了程序的可维护性.例子:一个电源总开关可以控制四盏灯.一个风扇.一台空调和一台电视机的启动和关闭.该电源总开关可以同时控制上述所有电器设备,电源总开关即为该系统的外观模式设计. 问题 为了降低复杂性,常常将系统划分为若干个子系统.但是如何做到各个系统之间的通信和相互依赖关系达到最小呢?  解决方案                                    

Android 适配器(Adapter)、观察者(Observer) 模式

适配器(Adapter)详述:http://blog.csdn.net/jjwwmlp456/article/details/39893723 观察者(Observer)详述:http://blog.csdn.net/jjwwmlp456/article/details/39967021 AdapterView 体系 AdapterView中会使用Adapter Adapter 体系 BaseAdapter 实现了 SpinnerAdapter.ListAdapter 这样的形式,就是 适配器模

Java 实现观察者(Observer)模式

1. Java自带的实现 类图 /** * 观察目标 继承自 java.util.Observable * @author stone * */ public class UpdateObservable extends Observable { private int data; public UpdateObservable(Observer observer) { addObserver(observer); /* * add other observer */ } public int

C++ 实现观察者(Observer)模式详解

观察者(Observer)模式,是常见的模式之一.比如一份报纸,有很多订户.订阅者并不知道报纸何时会送来,他只知道自己订了这份报纸.订阅者在这里担任着观察者的角色,而报社则是被观察者. 报纸一旦印刷完毕,就应该及时送到订户手中,如果将报社看作一个对象,则报纸便是观察者(订户)和被观察者(报社)之间的纽带.观察者需要维护一个与报纸相关的变量或函数,在这个具体问题中,这个变量就是订户是否收到报纸,可设置为一个布尔型,当收到时,订户需要更新这个变量. 下面是源码: // "Observer.H&quo

观察者(Observer)模式

观察者模式又叫做发布-订阅模式(Publish.Subscribe)模式.模型-视图模式(Model/View)模式.源-监听器模式(Source/Listener)模式或从属者(Dependents)模式. 观察者模式定义了一种一对多的依赖关系,让多个观察者同时监听某一个主题对象.这个主题对象在状态上发生变化时,会通知所有观察者对象,使它们能够自动更新自己. 1.  观察者模式结构 一个简单的观察者模型如下: 角色: 抽象(Subject)主题角色:把所有的观察者维持在一个集合中,每个主题都可

Android与设计模式——观察者(Observer)模式

在阎宏博士的<JAVA与模式>一书中开头是这样描述观察者(Observer)模式的: 观察者模式是对象的行为模式,又叫发布-订阅(Publish/Subscribe)模式.模型-视图(Model/View)模式.源-监听器(Source/Listener)模式或从属者(Dependents)模式. 观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象.这个主题对象在状态上发生变化时,会通知所有观察者对象,使它们能够自动更新自己. 观察者模式的结构 一个软件系统里面包含了

设计模式系列(二)原型模式

在设计模式系列(一)单例模式 中详细介绍了单例设计模式,下面一起来看一下原型模式. 一.概述 原型模式是一种创建型设计模式,它通过复制一个已经存在的实例来返回新的实例,而不是新建实例.被复制的实例就是我们所称的原型,这个原型是可定制的. 原型模式多用于创建复杂的或者耗时的实例, 因为这种情况下,复制一个已经存在的实例可以使程序运行更高效,或者创建值相等,只是命名不一样的同类数据. 二.深拷贝和浅拷贝 原型模式中的拷贝分为"浅拷贝"和"深拷贝": 浅拷贝: 对值类型的

设计模式实现(二)——策略模式的C++实现

一.策略模式的概念 在策略模式(Strategy Pattern)中,一个类的行为或其算法可以在运行时更改.这种类型的设计模式属于行为型模式. 在策略模式中,我们创建表示各种策略的对象和一个行为随着策略对象改变而改变的 context 对象.策略对象改变 context 对象的执行算法. 二.例子 (1) Strategy抽象类的实现 1 #ifndef STRATEGY_H 2 #define STRATEGY_H 3 4 class Strategy { 5 public: 6 Strate

设计模式之(二)---代理模式Proxy Pattern

什么是代理模式呢?我很忙,忙的没空理你,那你要找我呢就先找我的代理人吧,那代理人总要知道 被代理人能做哪些事情不能做哪些事情吧,那就是两个人具备同一个接口,代理人虽然不能干活,但是被 代理的人能干活呀. 比如西门庆找潘金莲,那潘金莲不好意思答复呀,咋办,找那个王婆做代理,表现在程序上时这样的: 先定义一种类型的女人(接口): package com.fc.Proxy; public interface KindWoman { public void makeEyesWithMan(); //抛媚