以天气预报项目引入观察者模式
传统方案

两个第三方网站
- public class Website1 {
- //温度
- private float temperature;
- //湿度
- private float humidity;
- //气压
- private float pressure;
-
- //修改气象数据
- public void update(float temperature, float humidity, float pressure){
- this.temperature = temperature;
- this.humidity = humidity;
- this.pressure = pressure;
- display();
- }
-
- //显示气象数据
- public void display(){
- System.out.println("----网站1气象数据服务----");
- System.out.println("温度:" + temperature);
- System.out.println("湿度:" + humidity);
- System.out.println("气压:" + pressure);
- }
- }
- public class Website2 {
- //温度
- public float temperature;
- //湿度
- public float humidity;
- //气压
- public float pressure;
-
- //修改气象数据
- public void update(float temperature, float humidity, float pressure){
- this.temperature = temperature;
- this.humidity = humidity;
- this.pressure = pressure;
- display();
- }
- //显示气象数据
- public void display(){
- System.out.println("----网站2气象数据服务----");
- System.out.println("温度:" + temperature);
- System.out.println("湿度:" + humidity);
- System.out.println("气压:" + pressure);
- }
- }
气象数据类,包含最新的天气情况信息,当数据有更新时,就主动的调用setData方法,这样第三方网站就能看到最新消息。
- public class WeatherData {
- //温度;
- private float temperature;
- //湿度;
- private float humidity;
- //气压;
- private float pressure;
-
- // 聚合第三方网站,方便通知最小消息
- private Website1 website1;
- private Website2 website2;
-
- public void setWebsite1(Website1 website1) {
- this.website1 = website1;
- }
-
- public void setWebsite2(Website2 website2) {
- this.website2 = website2;
- }
-
- //修改气象数据
- public void setData(float temperature, float humidity, float pressure){
- this.temperature = temperature;
- this.humidity = humidity;
- this.pressure = pressure;
- website1.update(temperature,humidity,pressure);
- website2.update(temperature,humidity,pressure);
- }
- }
测试
- public class Clint {
- public static void main(String[] args) {
-
- WeatherData weatherData = new WeatherData();
- Website1 website1 = new Website1();
- Website2 website2 = new Website2();
-
- weatherData.setWebsite1(website1);
- weatherData.setWebsite2(website2);
-
- //设置气象数据
- weatherData.setData(50.0f,50.0f,50.0f);
- //修改气象数据
- System.out.println("----气象台修改气象数据----");
- weatherData.setData(10.0f,10.0f,10.0f);
- }
- }
结果
----网站1气象数据服务----
温度:50.0
湿度:50.0
气压:50.0
----网站2气象数据服务----
温度:50.0
湿度:50.0
气压:50.0
----气象台修改气象数据----
----网站1气象数据服务----
温度:10.0
湿度:10.0
气压:10.0
----网站2气象数据服务----
温度:10.0
湿度:10.0
气压:10.0
问题分析
无法在运行时动态的添加第三方。
当增加一个第三方,需要修改气象数据类的方法,不利于维护。
观察者模式:对象之间多对一依赖的一种设计方案,被依赖的对象为 Subject,依赖的对象为 Observer,Subject 通知 Observer 变化,比如这里的气象数据是 Subject, 网站是Observer。

观察者接口:管理不同的用户
- // 观察者接口 --> 管理不同的用户
- public interface Observer {
- //更新天气数据;(温度,气压,湿度)
- public void update(float temperature, float humidity,float pressure);
- }
两个第三方网站
- public class Website1 implements Observer{
-
- //温度;
- private float temperature;
- //湿度;
- private float humidity;
- //气压;
- private float pressure;
-
- //更新气象数据;
- public void update(float temperature,float humidity,float pressure) {
- this.temperature = temperature;
- this.humidity = humidity;
- this.pressure = pressure;
- display();
- }
-
- //显示气象数据
- public void display(){
- System.out.println("----网站1气象数据服务----");
- System.out.println("温度:" + temperature);
- System.out.println("湿度:" + humidity);
- System.out.println("气压:" + pressure);
- }
- }
- public class Website2 implements Observer{
- //温度;
- private float temperature;
- //湿度;
- private float humidity;
- //气压;
- private float pressure;
-
- //更新气象数据;
- public void update(float temperature,float humidity,float pressure) {
- this.temperature = temperature;
- this.humidity = humidity;
- this.pressure = pressure;
- display();
- }
-
- //显示气象数据
- public void display(){
- System.out.println("----网站2气象数据服务----");
- System.out.println("温度:" + temperature);
- System.out.println("湿度:" + humidity);
- System.out.println("气压:" + pressure);
- }
- }
定义平台的管理接口
- public interface Subject {
- //注册,增加;
- public void registerObserver(Observer observer);
- //移出;
- public void remove(Observer observer);
- //通知所有的注册的用户
- public void notifyObserver();
- }
气象数据类
- public class WeatherData implements Subject{
- //温度;
- private float temperatrue;
- //湿度;
- private float humidity;
- //气压;
- private float pressure;
-
- //观察者(用户集合)
- private ArrayList
observerArrayList; -
- //初始化信息;
- public WeatherData() {
- observerArrayList = new ArrayList
(); - }
-
- //设置传入数据;
- public void setData(float temperature, float humidity, float pressure) {
- this.temperatrue = temperature;
- this.humidity = humidity;
- this.pressure = pressure;
- notifyObserver();
- }
-
- public void registerObserver(Observer observer) {
- observerArrayList.add(observer);
- }
-
- public void remove(Observer observer) {
- //若存在就移除;
- if(observerArrayList.contains(observer)){
- observerArrayList.remove(observer);
- }
- }
-
- public void notifyObserver() {
- for (int i = 0; i < observerArrayList.size(); i++) {
- observerArrayList.get(i).update(this.humidity, this.temperatrue, this.pressure);
- }
- }
- }
测试
- public class CLient {
- public static void main(String[] args) {
- WeatherData weatherData = new WeatherData();
- Website1 website1 = new Website1();
- Website2 website2 = new Website2();
-
- //添加发布的平台;
- weatherData.registerObserver(website1);
- weatherData.registerObserver(website2);
-
- //设置气象数据;
- weatherData.setData(31f,60f,180f);
-
- //修改气象数据
- weatherData.setData(20f,40f,60f);
- }
- }
结果
----网站1气象数据服务----
温度:31.0
湿度:60.0
气压:180.0
----网站2气象数据服务----
温度:31.0
湿度:60.0
气压:180.0
----网站1气象数据服务----
温度:20.0
湿度:40.0
气压:60.0
----网站2气象数据服务----
温度:20.0
湿度:40.0
气压:60.0
1)观察者模式设计后,会以集合的方式来管理用户(Observer),包括注册,移除和通知。
2)这样,我们增加观察者(这里可以理解成一个新的公告板),就不需要去修改核心类WeatherData,遵守了 ocp 原则。
Jdk 的 Observable 类就使用了观察者模式
- public class Observable {
- private boolean changed = false;
- private Vector
obs; -
-
- public Observable() {
- obs = new Vector<>();
- }
-
- public synchronized void addObserver(Observer o) {
- if (o == null)
- throw new NullPointerException();
- if (!obs.contains(o)) {
- obs.addElement(o);
- }
- }
-
- public synchronized void deleteObserver(Observer o) {
- obs.removeElement(o);
- }
-
- public void notifyObservers() {
- notifyObservers(null);
- }
-
- public void notifyObservers(Object arg) {
-
- Object[] arrLocal;
-
- synchronized (this) {
- if (!changed)
- return;
- arrLocal = obs.toArray();
- clearChanged();
- }
-
- for (int i = arrLocal.length-1; i>=0; i--)
- ((Observer)arrLocal[i]).update(this, arg);
- }
-
- public synchronized void deleteObservers() {
- obs.removeAllElements();
- }
-
- protected synchronized void setChanged() {
- changed = true;
- }
-
- protected synchronized void clearChanged() {
- changed = false;
- }
-
- public synchronized boolean hasChanged() {
- return changed;
- }
-
- public synchronized int countObservers() {
- return obs.size();
- }
- }
- public interface Observer {
-
- void update(Observable o, Object arg);
-
- }