介绍
观察者模式(又被称为发布-订阅(Publish/Subscribe)模式,属于行为型模式的一种,它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态变化时,会通知所有的观察者对象,使他们能够自动更新自己。
- Subject : 是主题,它把所有对观察者对象的引用文件存在了一个聚集里,每个主题都可以有任何数量的观察者。抽象主题提供了一个接口,可以增加和删除观察者对象
- Observer : 是抽象观察者,为所有的具体观察者定义一个接口,在得到主题的通知时更新自己
- ConcreteSubject : 是具体主题,将有关状态存入具体观察者对象,在具体主题内部状态改变时,给所有登记过的观察者发出通知
- ConcreteObserver : 是具体观察者,实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题的状态相协同。
案例
- 气象站可以将每天测量到的温度,湿度,气压等以公告的形式发布出去(比如第三方平台)。
- 需要设计第三方API,便于第三方也能接入获取天气数据。
- 提供温度,湿度,气压接口
- 测量数据更新时,需要时实时通知给第三方
创建Subject 接口
public interface Subject {
/**
* 注册观察者
*/
public void registerObserver(Observer observer);
/**
* 删除观察者
*/
public void removeObserver(Observer observer);
/**
* 通知观察者
*/
public void notifyObserver(float temperature, float pressure, float humidity);
}
创建ConcreteSubject 类实现 Subject接口
public class ConcreteSubject implements Subject {
//储存订阅
private List<Observer> observerList = new ArrayList<Observer>();
@Override
public void registerObserver(Observer observer) {
observerList.add(observer);
}
@Override
public void removeObserver(Observer observer) {
observerList.remove(observer);
}
@Override
public void notifyObserver(float temperature, float pressure, float humidity) {
observerList.stream().forEach( bean -> {
System.out.printf("通知订阅用户 :");
bean.update(temperature,pressure,humidity);
});
}
}
创建 Observer 接口
public interface Observer {
/**
* 更新
* @param temperature
* @param pressure
* @param humidity
*/
public void update(float temperature,float pressure,float humidity);
}
创建 ConcrereObserver 类 实现Observer接口
public class ConcrereObserver implements Observer{
private String name;
public ConcrereObserver(String name) {
this.name = name;
}
@Override
public void update(float temperature, float pressure, float humidity) {
CurrentCondition currentCondition = new CurrentCondition(name,temperature,pressure,humidity);
}
}
当前温度实体类
@Data
public class CurrentCondition {
private float temperature;
private float pressure;
private float humidity;
public CurrentCondition(String name,float temperature, float pressure, float humidity) {
this.temperature = temperature;
this.pressure = pressure;
this.humidity = humidity;
display(name);
}
private void display(String name) {
System.out.println("用户"+name);
System.out.println("Today :: 温度 :" + temperature);
System.out.println("Today :: 湿度 :" + humidity);
System.out.println("Today :: 气温 :" + pressure);
}
}
客户端
public class Client {
public static void main(String[] args) {
Subject concreteSubject = new ConcreteSubject();
ConcrereObserver concrereObserver = new ConcrereObserver("1");
ConcrereObserver concrereObserver2 = new ConcrereObserver("2");
concreteSubject.registerObserver(concrereObserver);
concreteSubject.registerObserver(concrereObserver2);
//通知用户
concreteSubject.notifyObserver(1,1,1);
}
}
优点和缺点
优点:
1)观察者模式后,会以集合的形式来管理用户(Observer), 包括注册、移除、通知
2)我们增加观察者,就不会去修改核心类的代码,保证来OCP原则
3)在同一个聚合上可以有多个遍历。
4)在迭代器模式中,增加新的聚合类和迭代器类都很方便,无须修改原有代码。
缺点:
1)如果观察者和观察目标间有循环依赖,可能导致系统崩溃
2)没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的
JDK中观察者的实现
public class Observable {
private boolean changed = false;
private Vector<Observer> obs;
/** Construct an Observable with zero Observers. */
public Observable() {
obs = new Vector<>();
}
……
}
Observable 类就使用了类观察者模式,其中obs 就是存放用户的集合Vector 包含 Observer
private Vector<Observer> obs;
public interface Observer {
/**
* This method is called whenever the observed object is changed. An
* application calls an <tt>Observable</tt> object's
* <code>notifyObservers</code> method to have all the object's
* observers notified of the change.
*
* @param o the observable object.
* @param arg an argument passed to the <code>notifyObservers</code>
* method.
*/
void update(Observable o, Object arg);
}
- Observable 相当于我们的Subject,Observable是类,不是接口,类中已经实现了方法(添加,删除,通知 等方法)
- Observer 即观察者模式中的Observer,有update方法
github Demo地址 : ~~~传送门~~~
个人博客地址:http://blog.yanxiaolong.cn/
评论