一、观察者模式(发布-订阅)介绍
1.1、观察者模式定义
定义对象间一对多或者一对一的依赖关系,主要用于1对N的通知。使得当每个对象状态发生改变时其相关依赖对象都得到通知并且被自动更新,又叫“发布——订阅”模式。属于对象行为型模式。
1.2、观察者模式动机
- 建立一种对象与对象之间的关系,一个对象发生改变时自动通知其对象,其他对象将相应作出反应;
- 发生改变的对象成为观察目标,被通知的对象称为观察者,观察者之间没有相互联系。
1.3、观察者模式的结构 / 角色
Subject:目标
ConcreteSubject:具体目标
Observer:观察者
ConcreteObserver:具体观察者
1.4、观察者模式优缺点
优点:
- 表现层和数据逻辑层分离,抽象了更新接口;
- 支持广播通信;
- 符合开闭原则要求。
缺点:
- 若观察者目标有很多观察者,将所有观察者都通知到位会很耗时间;
- 如果观察者和观察目标有循环依赖的话观察目标会触发他们之间循环调用,可能导致系统崩溃;
- 观察者只知道观察目标发生了变化却不知道怎么变化的。
1.5、两种实现方式
推:每次都会把通知广播的方式发送给所有观察者,所有观察者只能被动接收。
拉:观察者只要知道有情况即可,。至于什么时候获取内容、获取什么内容,可以自己决定。
1.6、观察者模式的使用环境 / 什么情况下用
- 一个抽象模型有两个方面,其中一个方面依赖于另一个方面;
- 一个对象的改变将导致起亚一个或者多个对象也发生改变,而不知道具体有多少独享将发生改变;
- 一个对象必须通知其他对象,而并不知道这些对象是谁;
- 需要在系统创建触发链,A对象行为影响B,B对象行为影响C...。
1.7、具体应用场景
关联行为场景,消息队列、消息总线等
二、代码示例
//1.观察者的接口,用来存放观察者共有方法
public interface Observer {
// 观察者方法
void update(Subjecct subjecct);
}
//2.观察对象的父类
public class Subjecct {
//观察者的存储集合
private List<Observer> list = new ArrayList<>();
// 注册观察者方法
public void registerObserver(Observer obs) {
list.add(obs);
}
// 删除观察者方法
public void removeObserver(Observer obs) {
list.remove(obs);
this.notifyAllObserver();
}
// 通知所有的观察者更新
public void notifyAllObserver() {
for (Observer observer : list) {
observer.update(this);
}
}
}
//3.具体观察者对象的实现
public class RealObserver extends Subjecct {
//被观察对象的属性
private int state;
public int getState(){
return state;
}
public void setState(int state){
this.state=state;
//主题对象(目标对象)值发生改变
this.notifyAllObserver();
}
}
public class Client {
public static void main(String[] args) {
// 目标对象
RealObserver subject = new RealObserver();
// 创建多个观察者
ObserverA obs1 = new ObserverA();
ObserverA obs2 = new ObserverA();
ObserverA obs3 = new ObserverA();
// 注册到观察队列中
subject.registerObserver(obs1);
subject.registerObserver(obs2);
subject.registerObserver(obs3);
// 改变State状态
subject.setState(300);
System.out.println(obs1.getMyState());
System.out.println(obs2.getMyState());
System.out.println(obs3.getMyState());
// 改变State状态
subject.setState(400);
System.out.println(obs1.getMyState());
System.out.println(obs2.getMyState());
System.out.println(obs3.getMyState());
}
}