在介绍这种写法之前,有必要介绍下函数式接口,函数式接口的概念由来已久,一般来说只定义了一个虚方法的接口就叫函数式接口,在Java8中,由于Lambda表达式的出现,让函数式接口大放异彩。
我们仅仅需要修改客户端的代码就可以:
public static void main(String[] args) { Subject subject = new NewsSubject(); subject.add(a -> System.out.println("已阅这新闻")); subject.add(a -> System.out.println("假的吧")); subject.add(a -> System.out.println("昨天就看过了")); subject.update(); }运行结果:
利用Lambda表达式和函数式接口,可以省去【具体观察者角色】的定义,但是个人认为,这并非属于严格意义上的观察者模式,而且弊端很明显:
客户端需要知道观察者的具体实现。
如果观察者的具体实现比较复杂,可能代码并没有那么清晰。
所以这种写法,具有一定的局限性。
借用大神的一句话
设计模式的出现,是为了弥补语言的缺陷。
正是由于语言的升级,让某些设计模式发生了一定的变化,除了观察者模式,还有模板方法模式、责任链模式等,都由于 Lambda表达式的出现,而出现了一些变化。
JDK在Java中,本身就提供了一个接口:Observer,一个子类:Observable,其中Observer表示【观察者】,Observable表示【主题】,可以利用这两个子类和接口来实现观察者模式:
public class NewsObservable extends Observable { public void update() { setChanged(); notifyObservers(); } } public class People1 implements Observer { @Override public void update(Observable o, Object arg) { System.out.println("小编真无聊"); } } public class People2 implements Observer { @Override public void update(Observable o, Object arg) { System.out.println("开局一张图,内容全靠编"); } }客户端:
public static void main(String[] args) { NewsObservable newsObservable = new NewsObservable(); newsObservable.addObserver(new People1()); newsObservable.addObserver(new People2()); newsObservable.update(); }运行结果:
在这里,我不打算详细介绍这种实现方式,因为从Java9开始,Java已经不推荐这种写法了,而推荐用消息队列来实现。是不是很开心,找到一个借口不去研究Observable,Observer 这两个东西了。
Spring中的事件编程模型Spring中的事件编程模型就是观察者模式的实现,SpringBoot就利用了Spring的事件编程模型来完成一些操作,这里暂时不表。
在Spring中定义了一个ApplicationListener接口,从名字就知道它是一个监听器,是监听Application的事件的,那么Application又是什么,就是ApplicationContext,ApplicationContext内置了几个事件,其中比较容易理解的是:
ContextRefreshedEvent
ContextStartedEvent
ContextStoppedEvent
ContextClosedEvent
从名称上来看,就知道这几个事件是什么时候被触发的了。
下面我演示下具体的用法,比如我想监听ContextRefreshedEvent事件,如果事件发生了,就打印一句话。
@Component public class MyListener implements ApplicationListener{ @Override public void onApplicationEvent(ApplicationEvent applicationEvent) { if(applicationEvent instanceof ContextRefreshedEvent){ System.out.println("刷新了"); } } } @Configuration @ComponentScan public class AppConfig { } public static void main(String[] args) { AnnotationConfigApplicationContext context=new AnnotationConfigApplicationContext(AppConfig.class); }运行结果: