观察者模式
观察者(Observer)模式又名发布-订阅(Publish/Subscribe)模式
定义:
GOF 给观察者模式如下定义:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象(观察者)会都得到通知并被自动更新。属于行为型模式.
组成:
- 在 Subject 这个抽象类中,提供了上面提到的功能,而且存在一个通知方法:notify。这样当具体目标角色的状态发生改变,按照约定则会去调用通知方法,在这个方法中则会根据目标角色中注册的观察者名单来逐个调用相应的update 方法来调整观察者的状态。这样观察者模式就走完了一个流程。
案例1:
1.面向对象的傻等
class Child {
private boolean cry = false;
public boolean isCry() {
return cry;
}
public void wakeUp() {
System.out.println("Waked Up! Crying wuwuwuwu...");
cry = true;
}
}
public class Main {
public static void main(String[] args) {
Child child = new Child();
while(!child.isCry()) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("observing...");
}
}
}
2.1加入观察者
class Child {
private boolean cry = false;
private Dad d = new Dad();
public boolean isCry() {
return cry;
}
public void wakeUp() {
cry = true;
d.feed();
}
}
class Dad {
public void feed() {
System.out.println("dad feeding...");
}
}
public class Main {
public static void main(String[] args) {
Child c = new Child();
//do sth
c.wakeUp();
}
}
2.2 加入多个观察者
class Child {
private boolean cry = false;
private Dad dad = new Dad();
private Mum mum = new Mum();
private Dog dog = new Dog();
public boolean isCry() {
return cry;
}
public void wakeUp() {
cry = true;
dad.feed();
dog.wang();
mum.hug();
}
}
class Dad {
public void feed() {
System.out.println("dad feeding...");
}
}
class Mum {
public void hug() {
System.out.println("mum hugging...");
}
}
class Dog {
public void wang() {
System.out.println("dog wang...");
}
}
public class Main {
public static void main(String[] args) {
Child c = new Child();
//do sth
c.wakeUp();
}
}
3.分离观察者与被观察者
class Child {
private boolean cry = false;
private List<Observer> observers = new ArrayList<>();
{
observers.add(new Dad());
observers.add(new Mum());
observers.add(new Dog());
}
public boolean isCry() {
return cry;
}
public void wakeUp() {
cry = true;
for(Observer o : observers) {
o.actionOnWakeUp();
}
}
}
interface Observer {
void actionOnWakeUp();
}
class Dad implements Observer {
public void feed() {
System.out.println("dad feeding...");
}
@Override
public void actionOnWakeUp() {
feed();
}
}
class Mum implements Observer {
public void hug() {
System.out.println("mum hugging...");
}
@Override
public void actionOnWakeUp() {
hug();
}
}
class Dog implements Observer {
public void wang() {
System.out.println("dog wang...");
}
@Override
public void actionOnWakeUp() {
wang();
}
}
public class Main {
public static void main(String[] args) {
Child c = new Child();
//do sth
c.wakeUp();
}
}
4.1有很多时候,观察者需要根据事件的具体情况来进行处理
class Child {
private boolean cry = false;
private List<Observer> observers = new ArrayList<>();
{
observers.add(new Dad());
observers.add(new Mum());
observers.add(new Dog());
}
public boolean isCry() {
return cry;
}
public void wakeUp() {
cry = true;
wakeUpEvent event = new wakeUpEvent(System.currentTimeMillis(), "bed");
for(Observer o : observers) {
o.actionOnWakeUp(event);
}
}
}
//事件类 fire Event
class wakeUpEvent{
long timestamp;
String loc;
public wakeUpEvent(long timestamp, String loc) {
this.timestamp = timestamp;
this.loc = loc;
}
}
interface Observer {
void actionOnWakeUp(wakeUpEvent event);
}
class Dad implements Observer {
public void feed() {
System.out.println("dad feeding...");
}
@Override
public void actionOnWakeUp(wakeUpEvent event) {
feed();
}
}
class Mum implements Observer {
public void hug() {
System.out.println("mum hugging...");
}
@Override
public void actionOnWakeUp(wakeUpEvent event) {
hug();
}
}
class Dog implements Observer {
public void wang() {
System.out.println("dog wang...");
}
@Override
public void actionOnWakeUp(wakeUpEvent event) {
wang();
}
}
public class Main {
public static void main(String[] args) {
Child c = new Child();
//do sth
c.wakeUp();
}
}
- 有很多时候,观察者需要根据事件的具体情况来进行处理
- 大多数时候,我们处理事件的时候,需要事件源对象
4.2
class Child {
private boolean cry = false;
private List<Observer> observers = new ArrayList<>();
{
observers.add(new Dad());
observers.add(new Mum());
observers.add(new Dog());
}
public boolean isCry() {
return cry;
}
public void wakeUp() {
cry = true;
wakeUpEvent event = new wakeUpEvent(System.currentTimeMillis(), "bed", this);
for(Observer o : observers) {
o.actionOnWakeUp(event);
}
}
}
class wakeUpEvent{
long timestamp;
String loc;
Child source;
public wakeUpEvent(long timestamp, String loc, Child source) {
this.timestamp = timestamp;
this.loc = loc;
this.source = source;
}
}
interface Observer {
void actionOnWakeUp(wakeUpEvent event);
}
class Dad implements Observer {
public void feed() {
System.out.println("dad feeding...");
}
@Override
public void actionOnWakeUp(wakeUpEvent event) {
feed();
}
}
class Mum implements Observer {
public void hug() {
System.out.println("mum hugging...");
}
@Override
public void actionOnWakeUp(wakeUpEvent event) {
hug();
}
}
class Dog implements Observer {
public void wang() {
System.out.println("dog wang...");
}
@Override
public void actionOnWakeUp(wakeUpEvent event) {
wang();
}
}
public class Main {
public static void main(String[] args) {
Child c = new Child();
//do sth
c.wakeUp();
}
}
- 事件也可以形成继承体系
- 抽象化,getSource();
4.3
class Child {
private boolean cry = false;
private List<Observer> observers = new ArrayList<>();
{
observers.add(new Dad());
observers.add(new Mum());
observers.add(new Dog());
observers.add((e)->{
System.out.println("ppp");
});
//hook callback function
}
public boolean isCry() {
return cry;
}
public void wakeUp() {
cry = true;
wakeUpEvent event = new wakeUpEvent(System.currentTimeMillis(), "bed", this);
for(Observer o : observers) {
o.actionOnWakeUp(event);
}
}
}
abstract class Event<T> {
abstract T getSource();
}
class wakeUpEvent extends Event<Child>{
long timestamp;
String loc;
Child source;
public wakeUpEvent(long timestamp, String loc, Child source) {
this.timestamp = timestamp;
this.loc = loc;
this.source = source;
}
@Override
Child getSource() {
return source;
}
}
interface Observer {
void actionOnWakeUp(wakeUpEvent event);
}
class Dad implements Observer {
public void feed() {
System.out.println("dad feeding...");
}
@Override
public void actionOnWakeUp(wakeUpEvent event) {
feed();
}
}
class Mum implements Observer {
public void hug() {
System.out.println("mum hugging...");
}
@Override
public void actionOnWakeUp(wakeUpEvent event) {
hug();
}
}
class Dog implements Observer {
public void wang() {
System.out.println("dog wang...");
}
@Override
public void actionOnWakeUp(wakeUpEvent event) {
wang();
}
}
public class Main {
public static void main(String[] args) {
Child c = new Child();
//do sth
c.wakeUp();
}
}
1. 在很多系统中,Observer模式往往和责任链共同负责对于事件的处理
2. 其中的某一个observer负责是否将事件进一步传递
案例 2
GUI编程–02–AWT.事件监听https://blog.csdn.net/weixin_48052161/article/details/117397603
1.点击一个button ,显示台打印相关信息
public class TsetActionEvent {
public static void main(String[] args) {
//按下按钮发生一些事件
Frame frame = new Frame();
Button button = new Button("please!");
//设置监听器
MyActionListener1 myActionListener = new MyActionListener1();
MyActionListener2 myActionListener2 = new MyActionListener2();
//加入监听
button.addActionListener(myActionListener);
button.addActionListener(myActionListener2);
frame.add(button);
frame.pack();
windowClose(frame);
frame.setBounds(300,300,500,500);
frame.setVisible(true);
}
//关闭窗体的事件
private static void windowClose(Frame frame){
frame.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
}
}
class MyActionListener1 implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("叮叮叮当 1 !!!");
}
}
class MyActionListener2 implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("boom boom 2 !!!");
}
}
上述监听器继承ActionListener ,是import
java.awt.提供的.我们只需要重写actionPerformed()方法就行.
2 .自定义监听器,实现button的观察者模式
import java.util.ArrayList;
import java.util.List;
public class Test01 {
public static void main(String[] args) {
Button b = new Button();
b.addActionListener(new MyActionListener());
b.addActionListener(new MyActionListener2());
b.buttonPressed();
}
}
class Button {
private List<ActionListener> actionListeners = new ArrayList<ActionListener>();
public void buttonPressed() {
ActionEvent e = new ActionEvent(System.currentTimeMillis(),this);
for(int i=0; i<actionListeners.size(); i++) {
ActionListener l = actionListeners.get(i);
l.actionPerformed(e);
}
}
public void addActionListener(ActionListener l) {
actionListeners.add(l);
}
}
interface ActionListener {
public void actionPerformed(ActionEvent e);
}
class MyActionListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
System.out.println("button pressed!");
}
}
class MyActionListener2 implements ActionListener {
public void actionPerformed(ActionEvent e) {
System.out.println("button pressed 2!");
}
}
class ActionEvent {
long when;
Object source;
public ActionEvent(long when, Object source) {
super();
this.when = when;
this.source = source;
}
public long getWhen() {
return when;
}
public Object getSource() {
return source;
}
}
观察者模式在源码中的应用
1.Spring源码中观察者模式体现
ApplicationContext 的事件机制就是观察者模式的实现 ,通过实现 ApplicationListener 的onApplicationEvent 方法。可以监听指定事件。注意实现完毕后要注入要spring容器
监听指定事件
public class ApplicationContextListener implements ApplicationListener<ContextRefreshedEvent> {
@Override
public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
System.out.println("输出contextRefreshedEvent 监听事件内容");
}
}
自定义事件
public class LocalEvent extends ApplicationEvent {
public LocalEvent(Object source) {
super(source);
}
}
监听所有事件
public class ApplicationContextListener2 implements ApplicationListener {
@Override
public void onApplicationEvent(ApplicationEvent applicationEvent) {
System.out.println("事件类型" + applicationEvent.getClass().getName());
}
}
深入源码理解事件监听执行流程
创建容器对象
public ClassPathXmlApplicationContext(
String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
throws BeansException {
super(parent);
setConfigLocations(configLocations);
if (refresh) {
// refresh
refresh();
}
}
org.springframework.context.support.AbstractApplicationContext
refresh方法:去掉了部分源码,重点展示与事件和监听相关的代码
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
try {
// 初始化事件广播器
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
// 将容器中的监听器放入事件广播器中
// Check for listener beans and register them.
registerListeners();
// Last step: publish corresponding event.
// 初始化完成后刷新
finishRefresh();
}
catch (BeansException ex) {
}
finally {
}
}
}
initApplicationEventMulticaster 方法
/**
* Initialize the ApplicationEventMulticaster.
* Uses SimpleApplicationEventMulticaster if none defined in the context.
* @see org.springframework.context.event.SimpleApplicationEventMulticaster
*/
protected void initApplicationEventMulticaster() {
// 获取 Bean 工厂
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
// 判断是否自定义了事件广播器
if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
this.applicationEventMulticaster =
beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
if (logger.isTraceEnabled()) {
logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
}
}
else {
// 没有自定义事件处理器就创建 SimpleApplicationEventMulticaster 事件广播器
this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
if (logger.isTraceEnabled()) {
logger.trace("No '" + APPLICATION_EVENT_MULTICASTER_BEAN_NAME + "' bean, using " +
"[" + this.applicationEventMulticaster.getClass().getSimpleName() + "]");
}
}
}
registerListeners 方法,将监听器添加到事件广播器中
/**
* Add beans that implement ApplicationListener as listeners.
* Doesn't affect other listeners, which can be added without being beans.
*/
protected void registerListeners() {
// Register statically specified listeners first.
for (ApplicationListener<?> listener : getApplicationListeners()) {
getApplicationEventMulticaster().addApplicationListener(listener);
}
// Do not initialize FactoryBeans here: We need to leave all regular beans
// uninitialized to let post-processors apply to them!
// 在 bean 工厂中获取实现了 ApplicationListener 的监听器
String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
// 事件广播器循环添加监听器
for (String listenerBeanName : listenerBeanNames) {
getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
}
// Publish early application events now that we finally have a multicaster...
Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
this.earlyApplicationEvents = null;
if (!CollectionUtils.isEmpty(earlyEventsToProcess)) {
for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
getApplicationEventMulticaster().multicastEvent(earlyEvent);
}
}
}
finishRefresh 初始化完成后刷新
/**
* Finish the refresh of this context, invoking the LifecycleProcessor's
* onRefresh() method and publishing the
* {@link org.springframework.context.event.ContextRefreshedEvent}.
*/
protected void finishRefresh() {
// Clear context-level resource caches (such as ASM metadata from scanning).
clearResourceCaches();
// Initialize lifecycle processor for this context.
initLifecycleProcessor();
// Propagate refresh to lifecycle processor first.
getLifecycleProcessor().onRefresh();
// Publish the final event.
// 发布 ContextRefreshedEvent 事件
publishEvent(new ContextRefreshedEvent(this));
// Participate in LiveBeansView MBean, if active.
LiveBeansView.registerApplicationContext(this);
}
根据事件类型来执行相应监听器的监听方法
SimpleApplicationEventMulticaster 中的 multicastEvent
@Override
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
// 获取事件类型
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
// 获取自定义任务执行器
Executor executor = getTaskExecutor();
// 循环监听器,如果自定义任务执行器不存在,就调用invokeListener()方法。看到最后是调用了 listener 的 onApplicationEvent 方法。
for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
if (executor != null) {
executor.execute(() -> invokeListener(listener, event));
}
else {
invokeListener(listener, event);
}
}
}
小结:
- 启动容器,获取监听器,将监听器添加到事件广播器中。
- 当调用发布事件方法时,由事件广播器对事件进行广播。
2. ZooKeeper源码中观察者模式体现
ZooKeeper作为分布式应用程序的协调服务,其最常用的功能便是观察者模式observe;
Watcher
- Watcher是Zookeeper用来实现distribute lock, distribute configure, distribute queue等应用的主要手段。
- 要监控data_tree上的任何节点的变化(节点本身的增加,删除,数据修改,以及孩子的变化)都可以在获取该数据时注册一个Watcher,这有很像Listener模式。一旦该节点数据变化,Follower会发送一个notification response,client收到notification响应,则会查找对应的Watcher并回调他们。 有以下接口可以注册Watcher:
- Stat exists(final String path, Watcher watcher)
- Stat exists(String path, boolean watch)
- void exists(String path, boolean watch, StatCallback cb, Object ctx)
- void exists(final String path, Watcher watcher, StatCallback cb, Object ctx)
- byte[] getData(final String path, Watcher watcher, Stat stat)
- byte[] getData(String path, boolean watch, Stat stat)
- void getData(final String path, Watcher watcher, DataCallback cb, Object ctx)
- void getData(String path, boolean watch, DataCallback cb, Object ctx)
- List getChildren(final String path, Watcher watcher)
- List getChildren(String path, boolean watch)
- void getChildren(final String path, Watcher watcher,ChildrenCallback cb, Object ctx)
- 如果参数需要传递watcher,则可以自己定义Watcher进行回调处理。
- 如果是Boolean型变量,当为true时,则使用系统默认的Watcher,系统默认的Watcher是在zookeeper的构造函数中传递的Watcher。如果Watcher为空或者Boolean变量时为false,则表明不注册Watcher。
- 如果获取数据后不需要关注该数据是否变化,就不需要注册Watcher。上面没有返回值的都是异步调用模式。需要注意的是,一旦Watcher被调用后,将会从map中删除,如果还需要关注数据的变化,需要再次注册。
Watcher的使用与注意事项 :
- .Watcher需要每次都要注册。
- .Watcher回调之后就销毁如果打算再次回调就需要再次注册
3.Dubbo源码中观察者模式体现
Dubbo 的 Provider 启动时,需要与注册中心交互,先注册自己的服务,再订阅自己的服务,订阅时,采用了观察者模式,开启一个 listener。注册中心会每 5 秒定时检查是否有服务更新,如果有更新,向该服务的提供者发送一个 notify 消息,provider 接受到 notify 消息后,即运行 NotifyListener 的 notify 方法,执行监听器方法。
Dubbo中使用观察者模式最典型的例子是RegistryService。消费者在初始化的时候回调用subscribe方法,注册一个观察者,如果观察者引用的服务地址列表发生改变,就会通过NotifyListener通知消费者。此外,Dubbo的InvokerListener、ExporterListener 也实现了观察者模式,只要实现该接口,并注册,就可以接收到consumer端调用refer和provider端调用export的通知。Dubbo的注册/订阅模型和观察者模式就是天生一对。
总结:
使用场景:
- 一个对象的改变将导致其他一个或多个对象也发生改变,而不知道具体有多少对象将发生改变,可以降低对象之间的耦合度。
- 一个对象必须通知其他对象,而并不知道这些对象是谁。
- 需要在系统中创建一个触发链,A对象的行为将影响B对象,B对象的行为将影响C对象……,可以使用观察者模式创建一种链式触发机制。
优点:
- 建立一套触发机制。
- Subject和Observer之间是松偶合的,分别可以各自独立改变。
- Subject在发送广播通知的时候,无须指定具体的Observer,Observer可以自己决定是否要订阅Subject的通知。
- 遵守大部分GRASP原则和常用设计原则,高内聚、低偶合。观察者和被观察者是抽象耦合的。
缺点:
- 如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。提高时间消耗及程序的复杂度
- 如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃。
- 观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。
注意事项:
- JAVA 中已经有了对观察者模式的支持类。
- 避免循环引用。
- 如果顺序执行,某一观察者错误会导致系统卡壳,一般采用异步方式。