Java设计模式-行为型设计模式-观察者模式
从这一专栏开始将学习设计模式,上课学习和自己总结归纳的笔记将总结出来供大家参考。
参考书籍:《设计模式就该这样学》
其他文章:
一、行为型设计模式
在GOF23种设计模式中,有三种类型的设计模式,分别是:创建型设计模式、结构型设计模式、行为型设计模式。
在GoF23种设计模式中属于行为型设计模式:
Chain of Responsibility ( 责任链模式 )、Command ( 命令模式 )、Interpreter ( 解释器模式 ) 、Iterator ( 迭代器模式 )、Mediator ( 中介者模式 ) 、Memento ( 备忘录模式 ) 、Observer ( 观察者模式 )、State ( 状态模式 ) 、Strategy ( 策略模式 )、TemplateMethod ( 模板方法 )、Visitor ( 访问者模式 )11种模式。
二、观察者模式
1.观察者模式定义
观察者模式(Observer Pattern):又叫做发布-订阅模式(Publish/Subscribe pattern)、模型-视图(Model/View pattern)。定义一种一对多的依赖关系,一个主题对象可以被多个观察值对象同时监听,使得每当主题对象状态变化时,所有依赖它的对象都会得到通知并被自动更新。
在GoF23种设计模式中属于行为型设计模式:
其中包括:Chain of Responsibility ( 责任链模式 )、Command ( 命令模式 )、Interpreter ( 解释器模式 ) 、Iterator ( 迭代器模式 )、Mediator ( 中介者模式 ) 、Memento ( 备忘录模式 ) 、Observer ( 观察者模式 )、State ( 状态模式 ) 、Strategy ( 策略模式 )、TemplateMethod ( 模板方法 )、Visitor ( 访问者模式 )11种模式。
2.观察者模式的角色
抽象主题(ISubject):指被观察的对象,一般是一个抽象类或者是接口,定义了增加、删除、通知观察者对象的方法。
具体主题(ConcreteSubject):具体被观察的对象,当其内部状态变化的时候,会通。已注册的观察者。
抽象观察者(IObserver):定义了响应通知的更新方法。
具体观察者(ConcreteObserver):当得到状态更新的通知时,会自动做出响应。
3.观察者模式的特点
优点:
观察者和被观察者是松耦合的,符合依赖倒置原则(高层模块不应该依赖底层模块,二者都应该依赖其抽象。抽象不应该依赖细节,细节应该依赖抽象);
分离了观察者和被观察者,并且建立了一套触发机制,使得被观察者数据的变化可以响应到多个观察者上;
实现了一对多的通信机制,支持事件处理机制,支持兴趣分发机制,当被观察者触发事件时,只有感兴趣的观察者可以接收到通知。
缺点:
如果观察者的数量过多,则事件通知会耗费更多的时长;
事件通知呈线性关系,如果其中一个观察者处理事件卡壳,则会影响后续的观察者修改该事件;
如果观察者和被观察者之间存在循环依赖,则可能导致两者之间循环调用导致系统崩溃。
观察者模式的应用场景:
起床闹钟设置(如果一个人设置了一个闹钟,那么便会被闹钟提醒,那么闹钟就是被观察者,用户就是观察者);
朋友圈点赞提醒(微信朋友圈点赞之后,你就是观察者,微信的那条朋友圈就是被观察者);
网购APP商品降价通知推送(网购平台上,关注某个商品,当商品降价时,会收到通知)。
4.观察者模式的类图
5.观察者模式的通用写法
/**
* 抽象观察者
*/
interface Observer{
void response();
}
/**
* 具体观察者A
*/
class ConcreteObserverA implements Observer{
@Override
public void response() {
System.out.println("具体观察者A作出反应!");
}
}
/**
* 具体观察者B
*/
class ConcreteObserverB implements Observer{
@Override
public void response() {
System.out.println("具体观察者B作出反应!");
}
}
/**
* 抽象主题(被观察者)
*/
abstract class Subject{
protected List<Observer> observers = new ArrayList<>();
/**
* 增加观察者方法
* @param observer
*/
public void add(Observer observer){
observers.add(observer);
}
/**
* 删除观察者方法
* @param observer
*/
public void remove(Observer observer){
observers.remove(observer);
}
/**
* 通知观察者方法
*/
public abstract void notifyObserver();
}
/**
* 具体目标(具体被观察者)
*/
class ConcreteSubject extends Subject{
@Override
public void notifyObserver() {
System.out.println("具体目标发生改变!");
System.out.println("----------------");
for(Observer obs : observers){
obs.response();
}
}
}
public class ObserverSimpleTest {
public static void main(String[] args){
Subject subject = new ConcreteSubject();
Observer observerA = new ConcreteObserverA();
Observer observerB = new ConcreteObserverB();
subject.add(observerA);
subject.add(observerB);
subject.notifyObserver();
}
}
6.观察者模式在Spring框架中的应用
观察者模式在Spring框架中的具体实现就是事件模型驱动开发
Spring中观察者模式的四个角色
1.事件(ApplicationEvent)
ApplicationEvent 是所有事件对象的父类,类似于被观察者要做的被观察的事情。
类似于上面通用写法中的:
用户可以通过继承ApplicationEvent,实现自定义事件。
下列描述了Spring提供的内置事件:
ContextRefreshedEvent:Spring容器刷新完成(所有bean都完成创建)的事件;
ContextClosedEvent:关闭Spring容器的时候的事件。
…等
2.事件发布(ApplicationEventPublisher/ApplicationContext)
ApplicationContext 是 Spring 中的核心容器,通过它的publishEvent()发布事件的通知给观察者(ApplicationListener)监听到(告诉观察者你需要观察哪个事件),因为事件创建好了不知道会不会被观察者观察到,所以会使用它。
3.事件监听(ApplicationListener)
ApplicationListener 事件监听器,也就是抽象观察者。继承自 jdk 的 EventListener,该类中只有一个方法 onApplicationEvent(),通过这个方法就是在事件执行的时候观察者要做的事情, 用户可以实现ApplicationListener接口进行事件监听(创建具体观察者)
4.事件多播器(ApplicationEventMulticaster)
ApplicationEventMulticaster 用于事件监听器的注册和事件的广播。等同于被观察者中的observers属性,监听器的注册、删除、把 Applicationcontext (被观察者)发布的事件广播给它的ApplicationListener(被观察者)列表(让他们进行链式调用)。
1.环境搭建
1.1创建配置类ExtConfig
@ComponentScan("com.wxr.ext")
@Configuration
public class ExtConfig {
}
1.2创建MyApplicationListener实现ApplicationListener接口
这就是用户自定义创建的具体观察者类
@Component
public class MyApplicationListener implements ApplicationListener<ApplicationEvent> {
/**
* 当容器中发布此事件以后,该方法出发
* 监听ApplicationEvent及下面的子事件
* 根据ApplicationEvent的继承关系:
* 例如:
* ContextRefreshedEvent:容器刷新完成(所有bean都完成创建)会发布这个事件
* ContextClosedEvent:关闭容器的时候会发布这个事件
* 步骤:
* 1.写一个监听器来监听某个事件(ApplicationEvent及其子类)
* 2.把监听器加入到容器中
* 3.只要容器中有相应类型的事件发布,我们就监听到这个事件
* @param event
*/
@Override
public void onApplicationEvent(ApplicationEvent event) {
System.out.println("收到事件:"+event);
}
}
1.3测试代码和结果
public class IocTest {
@Test
public void test02(){
AnnotationConfigApplicationContext ioc = new AnnotationConfigApplicationContext(ExtConfig.class);
//发布事件
ioc.publishEvent(new ApplicationEvent(new String("我发布的事件")) {
});
System.out.println("ioc容器创建完成");
ioc.close();
}
}
2.源码分析-ApplicationListener原理
根据三.1的输出结果,我们按照先后顺序从ContextRefreshedEvent,IocTest$1,ContextClosedEvent进行分析
执行步骤:
1.向spring容器中注册事件多播器(ApplicationEventMulticaster)
2.向spring容器