观察者模式
(一)概述:定义对象间的一种一对多的依赖关系,以便当一个对象的状态发生改变时,所有依赖于他的对象都能得到通知并自动刷新
(二)帮助理解:
报社的业务就是出版报纸。
向某家报社订阅报纸,只要他们有新报纸出版,就会给你送来。只要你是他们的订户、你就会一直收到新报纸。
当你不想再看报纸的时候,取消订阅,他们就不会再送新报纸来。
只要报社还在运营,就会一直有人(或单位)向他们订阅报纸或取消订阅报纸。
- 报社:被观察者
- 订户:观察者
- 一个报社对应多个订户
(三)角色
- Subject:抽象主题:(报社这个概念) 其中抽象出来报社所应该有的功能,例如删除和增加.抽象成方法,供以后的实现类进行实现.
- ConcreteSubject:具体主题(具体到某一个报社),实现抽象主题的抽象方法,当具体主题中的状态发生变化时,给所有的观察者(订户)发送通知.
- Observer:抽象观察者:,(人)他定义了一个更新接口,用于在主题更改时更新**
- ConcreteObserver:具体观察者(订户),实现抽象观察者的接口.
代码实现
抽象主题接口
/**
* * @author 借我丹青妙笔
* 抽象主题
*/
public interface Subject {
void addObserver(Observer observer);
void removeObserver(Observer observer);
void notifyObservers();
}
具体主题类
package com.zking.observer2;
import java.util.ArrayList;
import java.util.List;
/**
* * @author 借我丹青妙笔
* 具体实现主题:气象局
*/
public class WeatherData implements Subject {
double temperature;
double humidity;
List<Observer> Observers = new ArrayList<>();
public WeatherData(double temperature, double humidity) {
this.temperature = temperature;
this.humidity = humidity;
}
public void update(double temperature, double humidity) {
this.temperature = temperature;
this.humidity = humidity;// 气象局数据一改变,马上通知接入的第三方/观察者
notifyObservers();
}
@Override
public void addObserver(Observer observer) {
Observers.add(observer);
observer.update(this.temperature, this.humidity);
}
@Override
public void removeObserver(Observer observer) {
Observers.remove(observer);
}
@Override
public void notifyObservers() {
for (Observer observer : Observers) {
observer.update(this.temperature, this.humidity);
}
}
}
抽象观察者接口
package com.zking.observer2;
/**
*
* @author 借我丹青妙笔
*
*/
public interface Observer {
void display();
void update(double temperature, double humidity);
}
具体观察者类
package com.zking.observer2;
/**
*
* @author 借我丹青妙笔
*
*/
public class Baidu implements Observer {
double temperature;
double humidity;
@Override
public void display() {
System.out.println("百度温馨提示:当前温度:" + temperature + ",当前湿度:" + humidity);
}
@Override
public void update(double temperature, double humidity) {
this.temperature = temperature;
this.humidity = humidity;
this.display();
}
}
class Sina implements Observer {
double temperature;
double humidity;
@Override
public void display() {
System.out.println("新浪温馨提示:当前温度:" + temperature + ",当前湿度:" + humidity);
}
@Override
public void update(double temperature, double humidity) {
this.temperature = temperature;
this.humidity = humidity;
this.display();
}
}
测试类
package com.zking.observer2;
/**
*
* @author 借我丹青妙笔
*
*/
public class Client {
public static void main(String[] args) {
//实例化气象局(被观察者)
WeatherData weatherData = new WeatherData(30, 20);
//实例化观察者
Baidu baidu = new Baidu();
Sina sina = new Sina();
//为观察者提供气象服务
weatherData.addObserver(baidu);
weatherData.addObserver(sina);
System.out.println("----------------------------");
//更新气象信息
weatherData.update(10, 10);
System.out.println("----------------------------");
//停止为某观察者提供气象服务
weatherData.removeObserver(baidu);
//更新气象信息
weatherData.update(12, 12);
}
}
打印结果
百度温馨提示:当前温度:30.0,当前湿度:20.0
新浪温馨提示:当前温度:30.0,当前湿度:20.0
----------------------------
百度温馨提示:当前温度:10.0,当前湿度:10.0
新浪温馨提示:当前温度:10.0,当前湿度:10.0
----------------------------
新浪温馨提示:当前温度:12.0,当前湿度:12.0
为什么要使用观察者模式
观察者模式提供了一种对象设计、让主题和观察者之间松耦合。
- 关于观察者的一切,主题只知道观察者实现了某个接口(也就是Observer接口)。主题不需要知道观察者的具体类是谁、做了些什么或其他任何细节。
- 任何时候我们都可以增加新的观察者。因为主题唯一依赖的东西是一个实现Observer接口的对象列表,所以我们可以随时增加观察者。事实上,在运行时我们可以用新的观察者取代现有的观察者,主题不会受到任何影响。同样的,也可以在任何时候删除某些观察者。
- 有新类型的观察者出现时,主题的代码不需要修改。假如我们有个新的具体类需要当观察者,我们不需要为了兼容新类型而修改主题的代码,所有要做的就是在新的类里匕实现此观察者接口,然后注册为观察者即可。主题不在乎别的,它只会发送通知给所有实现了观察者接口的对象。
- 我们可以独立地复用主题或观察者。如果我们在其他地方需要使用主题或观察者,可以轻易地复用,因为二者并非紧耦合。
- 改变主题或观察者其中一方,并不会影响另一方。因为两者是松耦合的,所以只要他们之间的接口仍被遵守,我们就可以自由地改变他们。
注意事项
- Java中已经有了对观察者模式的支持类
- 避免循环引用
- 如果顺序执行,某一观察者错误会导致系统卡壳,所以一般采用异步方式.
应用场景
- JavaBcans
- RMI
- JDK源码中Observable类
声明:学习记录,若有错误,欢迎指正。
作者: 借我丹青妙笔