观察者模式(Observer) : 当存在一对多的关系, 一
发生了改变, 与其有关系的 多
也要执行相关的动作. 也叫做发布订阅模式, 属于对象行为模式.
设计模式-概述
结构
观察者模式有如下主要角色:
- 抽象主题(Subject) : 它提供了一个用于保存观察者对象的聚集类和增加、删除观察者对象的方法,以及通知所有观察者的抽象方法。
- 具体主题(ConcreteSubject) : 实现抽象目标中的通知方法,当具体主题的内部状态发生改变时,通知所有注册过的观察者对象。
- 抽象观察者(Observer) : 包含了一个更新自己的抽象方法,当接到具体主题的更改通知时被调用。
- 具体观察者(ConcreteObserver) : 实现抽象观察者中定义的抽象方法,以便在得到目标的更改通知时更新自身的状态。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| @startuml observer-1 !include common.cuml
Class(AbstractSubject,"抽象主题") << abstract >> { - observers: List<Observer> + add(Observer observer) : void + remove(Observer observer) : void + notifyAllObserver() : void abstract }
Class(ConcreteSubject,"具体主题") { + notifyAllObserver() : void }
note as N1 public void notifyAllObserver() { for (Observer observer : Observers) { observer.response(); } } end note
Interface(Observer,"抽象观察者") { + response() : void }
Class(ConcreteObserverA,"具体主题A") { + response() : void }
Class(ConcreteObserverB,"具体主题B") { + response() : void }
N1 -- ConcreteSubject AbstractSubject <|-- ConcreteSubject Observer --o AbstractSubject ConcreteObserverA ..|> Observer ConcreteObserverB ..|> Observer
@enduml
|
代码实现
- 创建一个主题
- 创建n个观察者, 对这个主题进行绑定.
- 这个主题可能在某时刻发生改变, 发生改变后可以调用
notifyObservers()
方法.
notifyObservers()
方法内部封装了通知各个观察者的逻辑.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
| package com.yuda.test;
import java.util.ArrayList; import java.util.Arrays; import java.util.List;
public class Main {
public static void main(String[] args) { Subject subject = new ConcreteSubject(); Observer observerA = new ConcreteObserverA(); Observer observerB = new ConcreteObserverB(); Observer observerN = new ConcreteObserverN(); subject.add(observerA, observerB, observerN); subject.notifyObservers(); } }
abstract class Subject { protected List<Observer> observerList = new ArrayList<>();
public void add(Observer... observer) { observerList.addAll(Arrays.asList(observer)); }
public void remove(Observer observer) { observerList.remove(observer); }
public abstract void notifyObservers(); }
class ConcreteSubject extends Subject {
@Override public void notifyObservers() { for (Observer observer : observerList) { observer.response(); } } }
interface Observer { void response(); }
class ConcreteObserverA implements Observer {
@Override public void response() { System.out.println("ConcreteObserverA.response"); } }
class ConcreteObserverB implements Observer {
@Override public void response() { System.out.println("ConcreteObserverB.response"); } }
class ConcreteObserverN implements Observer {
@Override public void response() { System.out.println("ConcreteObserverN.response"); } }
|
使用场景
- 各个观察者(Observer)需要是独立的, 没有先后顺序.
- 观察者个数可控, 触发观察者是通过循环来实现的, 如果太多循环起来特别慢.
- 观察者与主题之间不能存在循环引用, 否则出现主题变更=>触发观察者=>观察者触发主题变更=>…., 最终程序卡死.
具体应用
jdk中的 java.util.Observable
与 java.util.Observer
定义了观察者模式, 需要用可以直接实现接口
excel处理工具 poi
中的 DataFormatter
实现了 java.util.Observer
, 并且定义了一个内部类 LocaleChangeObservable
在适当的地方调用 checkForLocaleChange()
方法来触发 观察者的update()
.
1 2 3 4 5
| <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId> <version>3.17</version> </dependency>
|
Spring中的事件驱动模型, 主要类有: ApplicationEvent
, ApplicationListener
, ApplicationContext
, ApplicationEventMulticaster
.
- ApplicationEvent继承自jdk的EventObject,所有的事件都需要继承ApplicationEvent,并且通过source得到事件源.该类的实现类ApplicationContextEvent表示ApplicaitonContext的容器事件.
- ApplicationListener继承自jdk的EventListener,所有的监听器都要实现这个接口
- 事件机制的实现需要三个部分,事件源,事件,事件监听器,在上面介绍的ApplicationEvent就相当于事件,ApplicationListener相当于事件监听器,这里的事件源说的就是applicaitonContext.
- 属于事件广播器,它的作用是把Applicationcontext发布的Event广播给所有的监听器.