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: 10
detail2: 20
detail3: 30
已更新...
detail1: 100
detail2: 200
detail3: 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>();
}
@Override
public void registerObserver(InterfaceObserver observer) {
System.out.println("主体 新增注册中...");
observers.add(observer);
System.out.println("主体 新增注册成功!");
}
@Override
public void removeObserver(InterfaceObserver observer) {
System.out.println("主体 移除注册中...");
if (observers.contains(observer)){
observers.remove(observer);
System.out.println("主体 移除注册成功!");
} else {
System.out.println("主体 移除注册失败....目标不存在!");
}
}
// 推送
@Override
public 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
*/
@Override
public 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;
@Override
public 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: 10
detail2: 20
观察者2开始更新...
观察者2更新成功!
观察者2进行 [折线图] 展示:
detail1: 10
detail2: 20
主体 更新数据成功
主体 开始全局推送
观察者1开始更新...
观察者1更新成功!
观察者1进行 [环形图] 展示:
detail1: 100
detail2: 200
观察者2开始更新...
观察者2更新成功!
观察者2进行 [折线图] 展示:
detail1: 100
detail2: 200
主体 移除注册中...
主体 移除注册成功!
主体 更新数据成功
主体 开始全局推送
观察者2开始更新...
观察者2更新成功!
观察者2进行 [折线图] 展示:
detail1: 999
detail2: 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...