0.参考资料
1.概述
- 定义对象间的一种一对多(变化)的依赖关系,以便当一个对象(Subject)的状态发生改变时,所有依赖于它的对象都得到通知并自动更新。 ——《设计模式》GoF
1.1动机
- 在软件构建过程中,我们需要为某些对象建立一种“通知依赖关系” ——一个对象(目标对象)的状态发生改变,所有依赖于它的对象(观察者对象)都将得到通知。如果这样的依赖关系过于紧密,将使软件不能很好地抵御变化。
1.2结构
- 
2.要点总结
宏观架构
1. 使用面向对象的抽象,Observer模式使得我们可以独立地改变目标与观察者,从而使二者之间的依赖关系达致松耦合。1. 目标发送通知时,无需指定观察者,通知(可以携带通知信息作为参数)会自动传播。1. 观察者自己决定是否需要订阅通知,目标对象对此一无所知。1. Observer模式是基于事件的UI框架中非常常用的设计模式,也是MVC模式的一个重要组成部分。(JavaWeb中的Listener)
微观代码
1. <br />1. <br />1. <br />
3.案例
需求
- 天气预报项目需求,具体要求如下:- 1) 气象站可以将每天测量到的温度,湿度,气压等等以公告的形式发布出去(比如发布到自己的网站或第三方)。- 2) 需要设计开放型API,便于其他第三方也能接入气象站获取数据。- 3) 提供温度、气压和湿度的接口(模拟数据为: detail1, detail2...)- 4) 测量数据更新时,要能实时的通知给第三方
示意图
- 
代码
- (伪)被观察者
public class WeatherData {private int detail1;private int detail2;private int detail3;MyObserver subject;public WeatherData(MyObserver observer){this.subject = observer;}public WeatherData() {}void dataChange(int detail1, int detail2, int detail3){this.detail1 = detail1;this.detail2 = detail2;this.detail3 = detail3;subject.update(detail1,detail2,detail3);}}
- (伪)观察者
public class MyObserver {private int detail1;private int detail2;private int detail3;public void update(int detail1, int detail2, int detail3){this.detail1 = detail1;this.detail2 = detail2;this.detail3 = detail3;show();}public void show(){System.out.println("已更新...");System.out.println("detail1: " + detail1);System.out.println("detail2: " + detail2);System.out.println("detail3: " + detail3);}}
- 测试及结果
public class Client {public static void main(String[] args) {WeatherData weatherData = new WeatherData(new MyObserver());weatherData.dataChange(10, 20, 30);weatherData.dataChange(100, 200, 300);}}
已更新...detail1: 10detail2: 20detail3: 30已更新...detail1: 100detail2: 200detail3: 300
分析
- 问题:- 若需要给其它第三方接入气象站获取数据...- 无法在运行时动态的添加第三方 (新浪网站)- 违反ocp原则 =>观察者模式
4.使用模式
- 观察者模式:对象之间多对一依赖的一种设计方案,被依赖的对象为Subject,依赖的对象为Observer,Subject通知Observer变化,比如这里的天气监测站是Subject,是1的一方。用户时Observer,是多的一方
方案
- 气象局:Subject(主体)- 功能: 登记注册、移除和通知- registerObserver 注册- removeObserver 移除- notifyObservers() 通知所有的注册的用户,根据不同需求,可以是更新数据,让用 户来取,也可能是实施推送,看具体需求定- - 用户/第三方网站:Observer(观察者)- 功能: 接收更新- 
类图
- 
代码
- Subject(主体, 天气监测站)
// 抽象主体public interface InterfaceSubject {void registerObserver(InterfaceObserver observer);void removeObserver(InterfaceObserver observer);void notifyObserver();void update(int detail1, int detail2);}// 具体的一个主体类public class ConcreteSubject1 implements InterfaceSubject {// 基础的需要更新(推送)的信息int detail1;int detail2;// 观察者集合ArrayList<InterfaceObserver> observers;public ConcreteSubject1(){this.observers = new ArrayList<InterfaceObserver>();}@Overridepublic void registerObserver(InterfaceObserver observer) {System.out.println("主体 新增注册中...");observers.add(observer);System.out.println("主体 新增注册成功!");}@Overridepublic void removeObserver(InterfaceObserver observer) {System.out.println("主体 移除注册中...");if (observers.contains(observer)){observers.remove(observer);System.out.println("主体 移除注册成功!");} else {System.out.println("主体 移除注册失败....目标不存在!");}}// 推送@Overridepublic void notifyObserver() {System.out.println("主体 开始全局推送");for (InterfaceObserver observer : observers) {observer.update(this.detail1, this.detail2);}}// 主体更新数据public void update(int detail1, int detail2) {this.detail1 = detail1;this.detail2 = detail2;System.out.println("主体 更新数据成功");// 主动调用, 自动推送notifyObserver();}}
- Observer(观察者)
// 观察者基类public interface InterfaceObserver {// 本案例由主体调用, 推送更新void update(int detail1, int detail2);}// 具体的观察者(一号public class ConcreteObserver1 implements InterfaceObserver {// 需要更新的具体数据int detail1;int detail2;/*** 更新天气情况, 使用推送模式, 由 Subject主体 推送* @param detail1* @param detail2*/@Overridepublic void update(int detail1, int detail2) {System.out.println("观察者1开始更新...");this.detail1 = detail1;this.detail2 = detail2;System.out.println("观察者1更新成功!");show();}/*** 展示, 不同的观察者可以有不同的展示样式*/public void show() {System.out.println("观察者1进行 [环形图] 展示: ");System.out.println("detail1: " + detail1);System.out.println("detail2: " + detail2);}}// 观察者二号public class ConcreteObserver2 implements InterfaceObserver {int detail1;int detail2;@Overridepublic void update(int detail1, int detail2) {System.out.println("观察者2开始更新...");this.detail1 = detail1;this.detail2 = detail2;System.out.println("观察者2更新成功!");show();}public void show() {System.out.println("观察者2进行 [折线图] 展示: ");System.out.println("detail1: " + detail1);System.out.println("detail2: " + detail2);}}
- 测试
public class Client {public static void main(String[] args) {// 创建主体对象InterfaceSubject subject = new ConcreteSubject1();// 创建多个观察者对象InterfaceObserver observer1 = new ConcreteObserver1();InterfaceObserver observer2 = new ConcreteObserver2();// 主体对象注册观察者subject.registerObserver(observer1);subject.registerObserver(observer2);// 主体更新数据(内部自动推送)subject.update(10,20);subject.update(100,200);// 模拟移除注册subject.removeObserver(observer1);// 测试移除结果subject.update(999,123);}}
主体 新增注册中...主体 新增注册成功!主体 新增注册中...主体 新增注册成功!主体 更新数据成功主体 开始全局推送观察者1开始更新...观察者1更新成功!观察者1进行 [环形图] 展示:detail1: 10detail2: 20观察者2开始更新...观察者2更新成功!观察者2进行 [折线图] 展示:detail1: 10detail2: 20主体 更新数据成功主体 开始全局推送观察者1开始更新...观察者1更新成功!观察者1进行 [环形图] 展示:detail1: 100detail2: 200观察者2开始更新...观察者2更新成功!观察者2进行 [折线图] 展示:detail1: 100detail2: 200主体 移除注册中...主体 移除注册成功!主体 更新数据成功主体 开始全局推送观察者2开始更新...观察者2更新成功!观察者2进行 [折线图] 展示:detail1: 999detail2: 123
分析
- 观察者模式设计后,会以集合的方式来管理用户(Observer),包括注册,移除 和通知。- 这样,我们增加观察者(这里可以理解成一个新的公告板),就不需要去修改核心类WeatherData不会修改代码,遵守了ocp原则
5.经典使用
5.1Jdk的Observable类和Observer接口
- Observable 和 Observer 的使用方法和前面讲过的一样,只是Observable 是类,通过继承来实现观察者模式
Observer接口:
- Observer 的作用和地位等价于我们前面讲过的 Observer, 有update
:::info
public interface Observer {__ _void update(Observable o, Object arg);
}
:::
Observable类:
- - 分析- Observable 的作用和地位等价于前面的Subject- Observable 是类,不是接口,类中已经实现了核心的方法 ,即管理Observer的方法 add.. delete .. notify...
