Java设计模式(20)-观察者模式
很快又到年底了,一年一度的春节除了可以享受愉快地享受假期之外,每年的"春节联欢晚会"也是让人倍感期待。然而,大多数人都没能坐在电视机跟前等着它的开始,有的人在厨房忙着准备丰富的食物,有的在一起打麻将、玩牌,还有的可能在玩电脑游戏……大家都想看晚会,于是派出一个小朋友,告诉他:"如果晚会开始了,你要立刻来通知我们哦!"虽然,大家就可以继续做自己的事情,小朋友就坐在电视跟前,当晚会开始的时候,他就立即跑去挨个通知大家…… 观察者模式示意(图片来源网络) 模式源于生活,上边的这个场景,就是一个典型的观察者模式的例子。 1. 概念 先来看看观察者模式的定义。 DP 对观察者模式的定义 观察者模式(Observer),又叫发布-订阅(publish-subscribe)模式,定义了对象间的一种一对多的依赖关系,当一个对象发生改变时,所有依赖它的对象都得到通知并被自动更新。 生活中,有很多这样的一个对象依赖其他多个对象(一对多关系)的例子,该对象状态发生变化了,其他关联的对象都需要知道并且做出行动。如上边的小孩儿看到晚会开始了,要立即通知其他人,其他人可以选择去看春晚,也可以选择继续做自己的事情。又比如,路口红绿灯变绿时,意思是告诉大家可以通行了;微信群有人发消息了,群成员都可以看到这条消息,等等…… 在软件领域,观察者模式的运用非常多,如:消息队列(MQ) 可以视为观察者模式实现;又比如,响应式编程 的核心就是观察者模式。 2. 结构 观察者模式类图如下: 可以看到,观察者模式有4个角色: Subject: 抽象主题对象,又叫做被观察者(Observable),或者目标对象,定义了添加、删除和通知观察者的方法,知道注册的观察者列表 ConcreteSubject: 具体主题对象,实现 Subject,有自身的状态,状态变化后向各个 Observer 发出通知 Observer: 抽象观察者,定义观察者的通用接口,包含一个用于更新的 update 方法 ConcreteObserver: 具体观察者,实现 Observer,依赖 ConcreteSubject ,当 ConcreteSubject 变化时得到通知,自身也可以更改 ConcreteSubject 的状态,此时可以通知其他观察者更新 上边的几个角色,将抽象和实现相分离,主题对象和观察者都可以各自进行扩展。另外,并不总是主题对象调用 notify 方法去通知观察者们,观察者也可以调用它从而通知其他观察者。 优点: 观察者模式降低了对象间的耦合性,提高了复用性,符合依赖倒置原则 主题对象广播通知给所有观察者,并不关心具体的观察者是谁,易于添加和删除观察者,而具体的更新与否以及如何更新由观察者自身实现 缺点: 观察者自身并不知道其他观察者的存在,它对更改主题状态的代价一无所知,因此需要定义和维护依赖准则,否则可能引起错误更新 主题和观察者之间仍然存在耦合性(没有完全解耦),存在相互依赖关系甚至可能造成循环依赖 3. 适用场景 观察者模式的使用场景: 对象间存在一对多的依赖关系,双方都需要独立的扩展和复用 一个对象的改变会同时改变其他依赖对象 一个对象必须通知其他对象,但是并不知道其他对象具体是谁 4. 示例 接下来看看观察者模式的示例代码(注意,下边的代码没有考虑并发安全性)。 1、定义观察者 public interface Observer { void update(); (1) } ...