观察者模式使用的场景:当目标对象发生变更时,一个或多个观察者可以接收变更的事件,比如在MQ中一对一或一对多的发布订阅,及一个生产者对应一个或多个消费者
优点:由于建立了一对多的统一触发机制可以实现目标与观察者的解藕。
缺点:当有多个观察者时可能会影响执行效率,因为目标对象内部会有存储观察者实例的容器,所谓的触发及触发容器内部的实例,因此当实例过多时会比较耗时。
类图:
主要类及方法: 抽象目标:Subject
#add 新增观察者实例方法到容器中
#remove 移除观察者实例方法
#notifyObserver 唤醒、触发 容器中的观察者 会调具体目标中的相同方法达到和观察者实例解耦的目的
具体目标:ConcreteSubject
#notifyObserver 唤醒、触发 容器中的观察者
观察者接口:Observer
#response
观察者实例:ConcreteObserver1、ConcreteObserver2、ConcreteObserver3、、、、、
#response
使用:
public class ObserverTest {
public static void main(String[] args) {
//创建具体目标类
Subject subject = new ConcreteSubject();
//创建观察者实例
Observer obs1 = new ConcreteObserver1();
Observer obs2 = new ConcreteObserver2();
//添加观察者实例到抽象目标容器
subject.add(obs1);
subject.add(obs2);
//调具体目标的notifyObserver 触发观察者执行
subject.notifyObserver();
}
}
//具体目标
public class ConcreteSubject extends Subject {
@Override
public void notifyObserver() {
System.out.println("具体目标发生改变...");
//触发所有观察者执行
for (Object obs : observers) {
((Observer) obs).response();
}
}
}
//抽象目标
public abstract class Subject {
//存储观察者实例
protected List<Observer> observers = new ArrayList<Observer>();
//增加观察者方法
public void add(Observer observer) {
observers.add(observer);
}
//删除观察者方法
public void remove(Observer observer) {
observers.remove(observer);
}
public abstract void notifyObserver(); //通知观察者方法
}
//观察者接口
public interface Observer {
void response();//各实例处理逻辑
}
//观察者实现1
public class ConcreteObserver1 implements Observer {
@Override
public void response() {
System.out.println("观察者1具体实现的业务逻辑、、、、、、");
}
}
//观察者实现2
public class ConcreteObserver2 implements Observer {
@Override
public void response() {
System.out.println("观察者2具体实现的业务逻辑、、、、、、");
}
}
Java默认提供的观察者类及api:
目标类:Observable 其中包含 实例的新增、删除、触发 等方法
如下图所示:
1、Observable 的构造方法,在创建对象时会初始化 obs 容器
2、存储具体观察者实例的容器
3、新增观察者实例
4、删除观察者实例
5、触发观察者实例执行相应逻辑
6、changed 一个boolean类型的逻辑控制符
public void notifyObservers(Object arg) {
/*
* a temporary array buffer, used as a snapshot of the state of
* current Observers.
*/
Object[] arrLocal;
synchronized (this) {
//changed 使用的体现
if (!changed)
return;
arrLocal = obs.toArray();
clearChanged();
}
for (int i = arrLocal.length-1; i>=0; i--)
((Observer)arrLocal[i]).update(this, arg);
}
观察者接口:Observer 具体的观察者实例实现此方法及可
package java.util;
public interface Observer {
void update(Observable o, Object arg);
}
Guava提供的实现:
pom中引入对应的依赖
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>31.0.1-jre</version>
</dependency>
public class Guava {
public static void main(String[] args) {
EventBus eventBus = new EventBus();
GuavaEvent1 guavaEvent1 = new GuavaEvent1();
GuavaEvent2 guavaEvent2 = new GuavaEvent2();
eventBus.register(guavaEvent1);
eventBus.register(guavaEvent2);
eventBus.post("消息体");
}
static class GuavaEvent1 {
@Subscribe
public void subscribe(String arg) {
//接到通知后需要处理的具体业务逻辑
System.out.println("GuavaEvent1收到通知" + arg);
}
}
static class GuavaEvent2 {
@Subscribe
public void subscribe(String arg) {
//接到通知后需要处理的具体业务逻辑
System.out.println("GuavaEvent2收到通知" + arg);
}
}
}
控制台输出结果:
GuavaEvent1收到通知消息体
GuavaEvent2收到通知消息体
Process finished with exit code 0
Spring中观察者模式的使用? ApplicatcontextEvent
Redisson 中的发布订阅?