目录
前言
使用观察者模式,便能够在对象之间建立起一种一对多(主题与观察者)的依赖关系,当主题对象改变状态时,所有依赖它的观察者对象都会得到通知并且自动更新。
通过主题对象来使客户端与观察者对象之间的通信更加松散耦合、灵活可扩展。
一般用来解耦不同的业务逻辑,比如将实时更新、动态同步等功能与其它业务逻辑解耦。
可分为两种模式:推模型和拉模型
推模型
主题对象向观察者推送主题的详细信息,不管观察者是否需要,推送的信息通常是主题对象的全部或部分数据。
拉模型
主题对象在通知观察者的时候,只传递少量信息。如果观察者需要更具体的信息,由观察者主动到主题对象中获取,相当于是观察者从主题对象中拉数据。一般这种模型的实现中,会把主题对象自身通过update()方法传递给观察者,这样在观察者需要获取数据的时候,就可以通过这个引用来获取了。
UML
plantuml
@startuml 'https://plantuml.com/class-diagram interface Subject { + add(Observer) : void + remove(int) : void + notify() : void } class ConcreteSubject { - Observers : List<Observer> + add(Observer) : void + remove(int) : void + notify() : void } interface Observer { + update(Subject) : void } class ConcreteObserver { - field : type + update(Subject) : void } Subject <|.. ConcreteSubject Observer <|.. ConcreteObserver Subject "1" --> "n" Observer Observer ..> Subject @enduml
类图
实战代码
观察者模板
基于 JDK 的 Observable 和 Observer 接口 实现推模型观察者模式
Observable
public class CurrentTimeObservable extends Observable {
int hour;
public void updateHour() {
Calendar now = Calendar.getInstance();
this.hour = now.get(Calendar.HOUR_OF_DAY);
System.out.println("current hour: " + this.hour);
}
public void startNotify() {
setChanged();
notifyObservers(hour);
}
}
Observer
public class PeopleObserver implements Observer {
String name;
Map<Integer, String> schedule;
PeopleObserver(String name, Map<Integer, String> sourceMap) {
this.name = name;
schedule = new TreeMap<>(Comparator.comparingInt(o -> o));
schedule.putAll(sourceMap);
}
@Override
public void update(Observable o, Object arg) {
int hour = (int) arg;
String action = Optional.ofNullable(schedule.get(hour)).orElseGet(() ->
schedule.entrySet().stream()
.min((e1, e2) -> Math.abs(e1.getKey() - hour) <= Math.abs(e2.getKey() - hour) ? -1 : 1)
.get().getValue());
System.out.println(String.format("%s %s", name, action));
}
}
Client
public class Client {
public static void main(String[] args) {
Map<Integer, String> scheduleA = new HashMap<>();
scheduleA.put(8, "sleep");
scheduleA.put(9, "wake up");
scheduleA.put(12, "eat");
scheduleA.put(13, "work");
scheduleA.put(20, "study");
PeopleObserver people1 = new PeopleObserver("mike", scheduleA);
Map<Integer, String> scheduleB = new HashMap<>();
scheduleB.put(7, "sleep");
scheduleB.put(8, "wake up");
scheduleB.put(11, "eat");
scheduleB.put(12, "play");
PeopleObserver people2 = new PeopleObserver("tom", scheduleB);
CurrentTimeObservable currentTimeObservable = new CurrentTimeObservable();
currentTimeObservable.addObserver(people1);
currentTimeObservable.addObserver(people2);
currentTimeObservable.updateHour();
currentTimeObservable.startNotify();
}
}
Spring Event
Spring Event 是 Spring 框架的事件处理机制,建立在观察者模式的基础上,允许不同组件之间通过事件来通信,事件发送者通过容器发送事件,事件监听器负责监特定类型的事件,并执行事件触发时业务逻辑。
使用 Event 可以用来解耦业务逻辑,无需直接引用,事件发布者和事件监听者各自独立变化,不会互相影响,程序更加灵活和可扩展。
Event
public class MyEvent extends ApplicationEvent {
public MyEvent(Object source) {
super(source);
}
}
EventListener
@Component
public class MyEventListener {
@EventListener(MyEvent.class)
public void onApplicationEvent(MyEvent event) {
System.out.println("EventListener::onApplicationEvent");
}
}
Client
@Component
public class MyService {
@Autowired
ApplicationContext applicationContext;
public void dealBiz()
{
//业务逻辑处理
//发送事件
applicationContext.publishEvent(new MyEvent(null));
}
}