文章收录在 GitHub JavaKeeper ,N线互联网开发必备技能兵器谱
在软件系统中常常会有这样的需求:若是一个对象的状态发生改变,某些与它相关的对象也要随之作出相应的变化。html
观察者模式是使用频率较高的设计模式之一。java
观察者模式包含观察目标和观察者两类对象,一个目标能够有任意数目的与之相依赖的观察者,一旦观察目标的状态发生改变,全部的观察者都将获得通知。git
观察者模式(Observer Pattern): 定义对象间一种一对多的依赖关系,使得当每个对象改变状态,则全部依赖于它的对象都会获得通知并自动更新。 github
观察者模式是一种对象行为型模式。设计模式
观察者模式的别名包括发布-订阅(Publish/Subscribe)模式、模型-视图(Model/View)模式、源-监听器(Source/Listener)模式或从属者(Dependents)模式。安全
细究的话,发布订阅和观察者有些不一样,能够理解成发布订阅模式属于广义上的观察者模式。微信
update()
,所以又称为抽象观察者。再记录下 UML 类图的注意事项,这里个人 Subject 是抽象方法,因此用斜体,抽象方法也要用斜体,具体的各类箭头意义,我以前也总结过《设计模式前传——学设计模式前你要知道这些》(被网上各类帖子毒害过的本身,认真记录~~~)。多线程
一、定义观察者接口app
interface Observer { public void update(); }
二、定义被观察者测试
abstract class Subject { private Vector<Observer> obs = new Vector(); public void addObserver(Observer obs){ this.obs.add(obs); } public void delObserver(Observer obs){ this.obs.remove(obs); } protected void notifyObserver(){ for(Observer o: obs){ o.update(); } } public abstract void doSomething(); }
三、具体的被观察者
class ConcreteSubject extends Subject { public void doSomething(){ System.out.println("被观察者事件发生改变"); this.notifyObserver(); } }
四、具体的被观察者
class ConcreteObserver1 implements Observer { public void update() { System.out.println("观察者1收到信息,并进行处理"); } } class ConcreteObserver2 implements Observer { public void update() { System.out.println("观察者2收到信息,并进行处理"); } }
五、客户端
public class Client { public static void main(String[] args){ Subject sub = new ConcreteSubject(); sub.addObserver(new ConcreteObserver1()); //添加观察者1 sub.addObserver(new ConcreteObserver2()); //添加观察者2 sub.doSomething(); } }
输出
被观察者事件发生改变 观察者1收到信息,并进行处理 观察者2收到信息,并进行处理
经过运行结果能够看到,咱们只调用了 Subject
的方法,但同时两个观察者的相关方法都被调用了。仔细看一下代码,其实很简单,就是在 Subject
类中关联一下 Observer
类,而且在 doSomething()
方法中遍历一下 Observer
的 update()
方法就好了。
观察者模式在 Java 语言中的地位很是重要。在 JDK 的 java.util 包中,提供了 Observable 类以及 Observer 接口,它们构成了 JDK 对观察者模式的支持(能够去查看下源码,写的比较严谨)。but,在 Java9 被弃用了。
Spring 事件驱动模型也是观察者模式很经典的应用。就是咱们常见的项目中最多见的事件监听器。
Spring 也为咱们提供了不少内置事件,ContextRefreshedEvent
、ContextStartedEvent
、ContextStoppedEvent
、ContextClosedEvent
、RequestHandledEvent
。
ApplicationContext
是 Spring 中的核心容器,在事件监听中 ApplicationContext 能够做为事件的发布者,也就是事件源。由于 ApplicationContext 继承自 ApplicationEventPublisher。在 ApplicationEventPublisher
中定义了事件发布的方法:publishEvent(Object event)
一、定义事件
public class MyEvent extends ApplicationEvent { public MyEvent(Object source) { super(source); System.out.println("my Event"); } }
二、实现事件监听器
@Component class MyListenerA implements ApplicationListener<MyEvent> { public void onApplicationEvent(MyEvent AyEvent) { System.out.println("ListenerA received"); } } @Component class MyListenerB implements ApplicationListener<MyEvent> { public void onApplicationEvent(MyEvent AyEvent) { System.out.println("ListenerB received"); } }
三、事件发布者
@Component public class MyPublisher implements ApplicationContextAware { private ApplicationContext applicationContext; public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext=applicationContext; } public void publishEvent(ApplicationEvent event){ System.out.println("publish event"); applicationContext.publishEvent(event); } }
四、测试,先用注解方式将 MyPublisher 注入 Spring
@Configuration @ComponentScan public class AppConfig { @Bean(name = "myPublisher") public MyPublisher myPublisher(){ return new MyPublisher(); } }
public class Client { @Test public void main() { ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class); MyPublisher myPublisher = (MyPublisher) context.getBean("myPublisher"); myPublisher.publishEvent(new MyEvent(this)); } }
五、输出
my Event publish event ListenerA received ListenerB received
设计模式真的只是一种设计思想,不须要非得有多个观察者才能够用观察者模式,只有一个观察者,我也要用。
再举个栗子,我是作广告投放的嘛(广告投放的商品文件通常为 xml),假如个人广告位有些空闲流量,这我得利用起来呀,因此我就从淘宝客或者拼夕夕的多多客上经过开放的 API 获取一些,这个时候我也能够用观察者模式,每次请求 10 万条商品,我就生成一个新的商品文件,这个时候我也能够用观察者模式,获取商品的类是被观察者,写商品文件的是观察者,当商品够10万条了,就通知观察者从新写到一个新的文件。
大佬可能觉这么实现有点费劲,不用设计模式也好,或者用消息队列也好,其实都只是一种手段,选择适合本身业务的,开心就好。