java设计模式——观察者模式

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

  1. 气象站可以将每天测量到的温度,湿度,气压等等以公告的形式发布出去(比如发布到自己的网站或第三方)。
  2. 需要设计开放型 API,便于其他第三方也能接入气象站获取数据。
  3. 提供温度、气压和湿度的接口。
  4. 测量数据更新时,要能实时的通知给第三方。

天气预报设计方案 1-普通方案

  • 传统的设计方案
    java设计模式——观察者模式_第1张图片

  • 通过getxxx()方法,可以让第三方接入,并得到相关信息。

  • 当数据有更新时,调用dataChange()方法去更新数据,当第三方再次获取时,就能得到最新数据,当前,也可以是推送。
    java设计模式——观察者模式_第2张图片

  • CurrentConditions(当前天气情况)

  1. 代码实现:
package com.jinxu.observer;

/**
 * 类是核心
 * 1. 包含最新的天气情况信息 
 * 2. 含有 CurrentConditions 对象
 * 3. 当数据有更新时,就主动的调用   CurrentConditions对象update方法(含 display), 这样他们(接入方)就看到最新的信息
 * @author Administrator
 *
 */
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() {
		//调用 接入方的 update
		currentConditions.update(getTemperature(), getPressure(), getHumidity());
	}

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

package com.jinxu.observer;

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

package com.jinxu.observer;

public class Client {
	public static void main(String[] args) {
		//创建接入方 currentConditions
		CurrentConditions currentConditions = new CurrentConditions();
		//创建 WeatherData 并将 接入方 currentConditions 传递到 WeatherData中
		WeatherData weatherData = new WeatherData(currentConditions);
		
		//更新天气情况
		weatherData.setData(30, 150, 40);
		
		//天气情况变化
		System.out.println("============天气情况变化=============");
		weatherData.setData(40, 160, 20);
		

	}
}

问题分析

  1. 其他第三方接入气象站获取数据的问题。
  2. 无法在运行时动态的添加第三方。
  3. 违反 ocp原则=>观察者模式
    在 WeatherData中,当增加一个第三方,都需要创建一个对应的第三方的公告板对象,并加入到 dataChange,不
    利于维护,也不是动态加入
public void dataChange() {
currentConditions.update(getTemperature(), getPressure(), getHumidity());
}

观察者模式原理

  1. 观察者模式类似订牛奶业务。
  2. 奶站/气象局:Subject。
  3. 用户/第三方网站:Observer。

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

  1. registerObserver注册。
  2. removeObserver移除。
  3. notifyObservers()通知所有的注册的用户,根据不同需求,可以是更新数据,让用户来取,也可能是实施推送,看具体需求定。

Observer:接收输入

观察者模式:

对象之间多对一依赖的一种设计方案,被依赖的对象为 Subject,依赖的对象为 Observer,Subject通知 Observer变化,比如这里的奶站是 Subject,是 1的一方。用户时 Observer,是多的一方。

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

  1. 类图:
    java设计模式——观察者模式_第3张图片
  2. 代码实现
package com.jinxu.observer.improve;

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

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

package com.jinxu.observer.improve;

//接口, 让WeatherData 来实现 
public interface Subject {
	
	public void registerObserver(Observer o);
	public void removeObserver(Observer o);
	public void notifyObservers();
}

package com.jinxu.observer.improve;

import java.util.ArrayList;

/**
 * 类是核心
 * 1. 包含最新的天气情况信息 
 * 2. 含有 观察者集合,使用ArrayList管理
 * 3. 当数据有更新时,就主动的调用   ArrayList, 通知所有的(接入方)就看到最新的信息
 * @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;
	}

	public void dataChange() {
		//调用 接入方的 update

        notifyObservers();
	}

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

	//注册一个观察者
	@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);
		}
	}
}

package com.jinxu.observer.improve;

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 + "***");
	}

}

package com.jinxu.observer.improve;

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 + "***");
	}
}

package com.jinxu.observer.improve;

public class Client {

	public static void main(String[] args) {

		//创建一个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);
	}

}

观察者模式的好处

  1. 观察者模式设计后,会以集合的方式来管理用户(Observer),包括注册,移除和通知。
  2. 这样,我们增加观察者(这里可以理解成一个新的公告板),就不需要去修改核心类 WeatherData不会修改代码,遵守了 ocp原则。

java设计模式往期回顾:

  • 设计模式原则demo示例下载
  1. java设计模式
  2. java设计模式原则——单一职责原则
  3. java设计模式原则——接口隔离原则
  4. java设计模式原则——依赖倒置原则
  5. java设计模式原则——里氏替换原则
  6. java设计模式原则——开闭原则
  7. java设计模式原则——迪米特法则
  8. java设计模式原则——合成复用原则
  9. java设计模式概述和分类
  10. java设计模式——单例模式
  11. java设计模式——工厂模式
  12. java设计模式——原型模式
  13. java设计模式——建造者模式
  14. java设计模式——适配器模式
  15. java设计模式——桥接模式
  16. java设计模式——装饰者模式
  17. java设计模式——组合模式
  18. java设计模式——外观模式
  19. java设计模式——享元模式
  20. java设计模式——代理模式
  21. java设计模式——模板方法模式
  22. java设计模式——命令模式
  23. java设计模式——访问者模式
  24. java设计模式——迭代器模式

你可能感兴趣的:(java设计模式)