一、概念
观察者一般可以看做是第三者,比如在学校上自习的时候,大家肯定都有过交头接耳、各种玩耍的经历,这时总会有一个“放风”的小伙伴,当老师即将出现时及时“通知”大家老师来了。再比如,拍卖会的时候,大家相互叫价,拍卖师会观察最高标价,然后通知给其它竞价者竞价,这就是一个观察者模式。
观察者模式(Observer):定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并自动更新。结构图如下:
观察者模式的主要角色如下:
- 抽象主题(Subject)角色:也叫抽象目标类,它提供了一个用于保存观察者对象的聚集类和增加、删除观察者对象的方法,以及通知所有观察者的抽象方法。
- 具体主题(Concrete Subject)角色:也叫具体目标类,它实现抽象目标中的通知方法,当具体主题的内部状态发生改变时,通知所有注册过的观察者对象。
- 抽象观察者(Observer)角色:它是一个抽象类或接口,它包含了一个更新自己的抽象方法,当接到具体主题的更改通知时被调用。
- 具体观察者(Concrete Observer)角色:实现抽象观察者中定义的抽象方法,以便在得到目标的更改通知时更新自身的状态。
二、实践
例子:天气观测站和气象报告板的关系。但报告板想获取观测站的数据,可以注册加入到观测站的观察者列表中,这就可以使观测站有数据更新时,自动传给气象报告板。
主题接口
package observe;
/**
* 主题
*
*/
public interface Subject {
//注册观察者
public void registerObserver(Observer o);
//移除观察者
public void removeObserver(Observer o);
//更新观察者
public void notifyObserver();
}
主题实现类:天气各类数据
package observe;
import java.util.ArrayList;
/**
* 实现Subject
*/
public class WeatherData implements Subject{
private ArrayList<Observer> observers; //观察者数组
private float temp;
private float humidity;
private float pressure;
public WeatherData() {
observers = new ArrayList<Observer>();
}
//增加一个观察者
public void registerObserver(Observer o) {
observers.add(o);
}
//移除一个观察者
public void removeObserver(Observer o) {
int i = observers.indexOf(o);
observers.remove(i);
}
//通知观察者
public void notifyObserver() {
for (int i = 0; i < observers.size(); i++) {
Observer observer = observers.get(i);
observer.update(temp,humidity,pressure);
}
System.out.println("更新数据~~~");
}
public void measurementChanged(){
//通知观察者
notifyObserver();
}
// 设置值
public void setMeasurements(float temp,float humidity,float pressure){
this.temp = temp;
this.humidity = humidity;
this.pressure = pressure;
measurementChanged();
}
}
观察者接口:用于更新数据
package observe;
/**
* 观察者
*/
public interface Observer {
public void update(float temp,float humidity,float pressure);
}
展示接口:用于显示数据
package observe;
public interface Display {
//展示的接口
public void display();
}
观察者实现类
package observe;
/**
* 基础的预测值
*/
public class BasicDisplay implements Display,Observer{
private float temp;
private float humidity;
private float pressure;
public void display() {
System.out.println("BasicDisplay{" +
"temp=" + temp +
", humidity=" + humidity +
", pressure=" + pressure + "}");
}
public void update(float temp, float humidity, float pressure) {
this.temp = temp;
this.humidity = humidity;
this.pressure = pressure;
display();
}
}
测试数据
package observe;
/**
* 测试数据
*/
public class WeatherStation {
public static void main(String[] args) {
WeatherData weatherData = new WeatherData();
BasicDisplay basicDisplay = new BasicDisplay();
weatherData.registerObserver(basicDisplay);
weatherData.setMeasurements(1f,2f,3f);
}
}
三、应用场景
支付场景
在支付场景下,用户购买一件商品,当支付成功之后三方会回调自身,在这个时候系统可能会有很多需要执行的逻辑(如:更新订单状态,发送邮件通知,赠送礼品…),这些逻辑之间并没有强耦合,因此天然适合使用观察者模式去实现这些功能,当有更多的操作时,只需要添加新的观察者就能实现,完美实现了对修改关闭,对扩展开放的开闭原则。
UGC场景
在一个UGC场景下,用户发布的内容往往会经过很多流程,大部分是先发往审核系统,当审核通过之后就会出现一系列的业务逻辑,比如更新内容状态,通知给所有的粉丝等等。