小言_互联网的博客

程序员必知的23种设计模式之观察者模式

434人阅读  评论(0)

1. 模式引出–天气预报项目需求

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

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

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

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

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

1.1 天气预报普通设计方案

通过对气象站项目的分析,我们可以初步设计出一个WeatherData类

说明:

  1. 通过getXxx方法,可以让第三方接入,并得到相关信息.

  2. 当数据有更新时,气象站通过调用dataChange() 去更新数据,当第三方再次获取时,就能得到最新数据,当然也可以推送

1.2 代码实现

WeatherData.java

/**
 * 类是核心 
 * 1.包含最新的天气情况信息 
 * 2.含有CurrentConditions对象
 * 3.当数据有更新时,就主动的调用CurrentConditions对象 update方法(含display),这样他们(接入方)就看到最新的信息
 * 
 * @author ACER1
 *
 */
public class WeatherData {
	private float temperatrue;
	private float pressure;
	private float humidity;
	private CurrentConditions currentConditions;

	public WeatherData(CurrentConditions currentConditions) {
		this.currentConditions = currentConditions;
	}

	public float getTemperature() {
		return temperatrue;
	}

	public float getPressure() {
		return pressure;
	}

	public float getHumidity() {
		return humidity;
	}

	public void dataChange() {
		currentConditions.update(getTemperature(), getPressure(), getHumidity());
	}

	public void setData(float temperature, float pressure, float humidity) {
		this.temperatrue = temperature;
		this.pressure = pressure;
		this.humidity = humidity;
		//调用dataChange,将最新的信息推送给接入方
		dataChange();
	}
}

CurrentConditions.java

/**
 * 显示当前天气情况(可以理解成是气象站自己的网站)
 * 
 * @author ACER1
 *
 */
public class CurrentConditions {
	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 + "***");
	}
}

测试Main.java

public class Main {
	public static void main(String[] args) {
		// 创建接入方currentConditions
		CurrentConditions currentConditions = new CurrentConditions();
		
		// 创建WeatherData并将接入方currentConditions传递到WeatherData中
		WeatherData weatherData = new WeatherData(currentConditions);

		// 更新天气情况
		weatherData.setData(30, 150, 40);
	}
}

输出结果

问题分析

  1. 其他第三方接入气象站获取数据的问题

  2. 无法在运行时动态的添加第三方 (新浪网站)

  3. 违反ocp原则=>观察者模式

2. 观察者模式原理

对象之间多对一依赖的一种设计方案,被依赖的对象为Subject,依赖的对象为Observer,Subject通知Observer变化.

Subject:登记注册、移除和通知

Observer:接收输入

3. 观察者模式解决天气预报需求

UML类图

Observer.java

// 观察者接口
public interface Observer {
	public void update(float temperature,float pressure,float humidity);
}

Subject.java

// 主题接口
public interface Subject {
	// 注册
	public void registerObserver(Observer o);

	// 移除
	public void removeObserver(Observer o);
	
	// 通知
	public void notigyObserver();

}

CurrentConditions.java

// 具体观察者
public class CurrentConditions implements Observer {
	private float temperature;
	private float pressure;
	private float humidity;
	private String name;

	public CurrentConditions(String name) {
		this.name = name;
	}

	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(name + ": Today mTemperature: " + temperature );
		System.out.println(name + ": Today mPressure: " + pressure);
		System.out.println(name + ": Today mHumidity: " + humidity);
	}
}

WeatherData.java

// 被观察的主题
public class WeatherData implements Subject {
	private float temperatrue;
	private float pressure;
	private float humidity;
	private List<Observer> observers;

	public WeatherData(List<Observer> observers) {
		this.observers = observers;
	}

	public float getTemperature() {
		return temperatrue;
	}

	public float getPressure() {
		return pressure;
	}

	public float getHumidity() {
		return humidity;
	}


	public void setData(float temperature, float pressure, float humidity) {
		this.temperatrue = temperature;
		this.pressure = pressure;
		this.humidity = humidity;
		
		notigyObserver();
	}

	@Override
	public void registerObserver(Observer o) {
		observers.add(o);
	}

	@Override
	public void removeObserver(Observer o) {
		observers.remove(o);
	}

	@Override
	public void notigyObserver() {
		for (Observer o : observers) {
			o.update(temperatrue, pressure, humidity);
		}
	}
}

测试Main.java

public class Main {
	public static void main(String[] args) {
		
		Observer a = new CurrentConditions("a");
		Observer b = new CurrentConditions("b");
		List<Observer> list = new ArrayList<>();
		list.add(a);
		list.add(b);
		WeatherData weatherData = new WeatherData(list);
		weatherData.setData(1, 1, 1);
		weatherData.removeObserver(b);
		System.out.println();
		weatherData.setData(2, 2, 2);
	}
}

输出结果

4. 观察者模式的好处

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

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

5. 观察者模式在Jdk1.8的应用

在jdk1.8中,有一个Observable类:

public class Observable {
    private boolean changed = false;
    private Vector<Observer> obs;
    public Observable() {
        obs = new Vector<>();
    }
    ...
}

可以看到其中有一个obs的属性成员,范型类型为Observer,并在类初始化时完成空间申请。

开始追Observer代码

public interface Observer {
    void update(Observable o, Object arg);
}

可以看到,Observer是一个接口,其中只有一个方法,update,和上例定义的的观察者接口时一样的功能。

回来看Observable类,Observable类并没有实现那个主题接口,而是直接充当了具体主题,可以看到Observable类中实现的方法列表

在其中可以看到主要的方法

addObserver(Observer)

deleteObserver(Observer)

notifyObservers()

使用java1.8提供的Observable类可以直接实现观察者模式,不需要重新构建

小结

  • Observable 的作用和地位等价于前面的Subject
  • Observable 是类,不是接口,类中已经实现了核心的方法 ,即管理Observer的方法 add… delete … notify…
  • Observer 的作用和地位等价于前面的 Observer, 有update
  • Observable Observer 的使用方法和前面的一样,只是Observable 是类,通过继承来实现观察者模式

转载:https://blog.csdn.net/qq_40963076/article/details/106259506
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场