如何让孩子爱上设计模式 ——15.观察者模式(Observer
标签: 设计模式初涉
描述性文字
本节讲述的是:观察者模式(Observer Pattern),如果你用过RxJava,相信你对
这个模式应该不会陌生,当然,RxJava是扩展的观察者模式,这里不做了解,只
讲解最简单的观察者模式,首先是使用场景,举个最简单的例子,你放学到家,
很饿,这个时候你妈在厨房做饭,因为你和妈妈达成了写完作业才可以玩农药的
约定,所以你要先写作业,但是你又很饿,你想当饭做好了第一时间能吃到,你
可以:
- 每隔一段时间跑去厨房找你妈,问她饭做好没(轮询)
- 跟你妈说一声,"老妈,饭做好了马上叫我"(订阅或注册),你妈答应了你
的请求,等她做完饭后立马通知你,这样你就不可以一心一意的做作业了,
等你妈通知你,然后放下手上的作业,去吃饭。
上面的场景,使用观察者模式,比起反复的检索,显得更加优雅。
这个模式,有两个主要角色:被观察者 与 观察者,这里的老妈就属于
被观察者,而你属于观察者,可能你还有个妹妹和弟弟,一起等饭吃,即:
一个被观察者可以对应多个观察者,你妈做好饭的时候,会把你们都通知一遍。
主要角色就这两个,当然,按照设计模式的套路,肯定是会抽象的,
所以有了另外的两个抽象被观察者,抽象观察者,四个角色责任如下:
四个角色
-
Subject:抽象被观察者,把所有观察者对象的引用保存到集合中,然后
提供添加,移除,和通知观察者对象更新的方法。 -
ConcreteSubject:被观察者,集合存放观察者,重写增删和通知观察者
的方法,当发生变化时通知观察者更新。 - Observer:抽象观察者,定义一个更新接口,给被观察者更新的时候调
- ConcreteObserver:具体观察者,继承抽象观察者,实现具体的更新方法
一条简单的笔试题示例
先不画UML类图,我们来写个最简单的观察者模式例子,这个题目是上周去随手记
笔试的题目,大概题目是这样的:
花有两种状态,开和关,对于这两种状态,蜜蜂有两种行为,花开的时候采蜜,
花关的时候回巢这样,然后自己设计类结构,花与蜜蜂解耦,要用到一种设计模式
实现,输出如下结果,并画出UML类图。
花开
蜜蜂1采蜜
蜜蜂2采蜜
蜜蜂3采蜜
花闭
蜜蜂1回巢
蜜蜂2回巢
蜜蜂3回巢
题目内容大概是这个样子,看完地图第一个想到的设计模式就是观察者模式,
套路:把花假定为被观察者,蜜蜂为观察者,蜜蜂对花进行订阅,当花的
状态改变的时候通知蜜蜂做对应操作。
(因为当时刚从珠海过来,而且浪了一周,基本是裸面,知道这个东西,但是
写不出代码,2333,贼尴尬,后来通过接口回调的方式实现了...)
下面就用观察者模式实现上面的题目,首先定义一个抽象观察者——昆虫类
然后是具体观察类——蜜蜂类
接着是抽象被观察者 —— 植物类,注册,移除,通知观察者
再接着是具体被观察者 —— 花朵类,定义一个集合存储观察者,实现相关方法
最后是客户端调用
输出结果:
好的,用观察者模式实现就这么简单,代码都有了,画UML类图就手到擒来了~
UML类图
观察者模式的推与拉
推方式
被观察者对象向观察者推送主题的详细信息,不管观察者是否需要,
推送的信息通常是被观察者对象的全部或部分数据。
拉方式
被观察者对象再通知观察者时,只传递少量信息。如果观察者需要更
详细的信息,可以主动到被观察者中获取,相当于观察者从被观察者
中拉取数据。一般的套路是:把主题对象自身通过update()方法传递
给观察者,然后观察者在需要获取的时候,通过这个引用来获取。
拉方式代码示例:
微信订阅了某个公众号,当有更新的时候会推送提醒,收到提醒后,
我们需要进入公众号然后点击对应信息查看详细内容。
抽象观察者用户与具体观察者安卓开发者
抽象被观察者公众号与具体被观察者CoderPig公众号
客户端调用
输出结果
好的,拉的模式就那么简单,就是通知观察者更新的时候,把对应引用
也传过去,然后观察者要什么查什么而已。
Java中对观察者模式的支持
在java.util包里面有一个类Observable,它实现了大部分我们需要的目标的功能;
还有一个接口Observer,它里面定义了update的方法,就是观察者的接口。
这个就更加简单了:
口诀:被观察者实现继承Observable,观察者实现Observer接口
然后有个很关键的地方:当通知变化的时候,需要调用setChange()方法!!!!
改写下上面的例子,代码如下:
输出结果
好的,同样很简单,就是不用自己另外去写抽象观察者或被观察者类,直接
继承就能玩了,另外有一点要注意的是:Java内置的观察者模式通知多个观察
者的顺序不是固定的,如果对通知顺序有所依赖的话,还是得自己实现观察者
模式!
概念相关拾遗
关于观察者模式的使用基本就上面这三点,接着说下定义,使用场景,优缺点
定义
定义对象见的一种一对多的依赖关系,当一个对象的状态发生改变时,
所有依赖于它的对象都得到通知并且自动更新。
使用场景
- 一个抽象模型有两个方面,其中一个方面依赖于另一个方面,将这两个方面封装在独立
的对象中使它们可以各自独立地改变和复用。 - 一个对象的改变将导致一个或多个其他对象也发生改变,而并不知道具体有多少对象将
发生改变,也不知道这些对象是谁。 - 需要在系统中创建一个触发链,A对象的行为将影响B对象,B对象的行为将影响C对象……,
可以使用观察者模式创建一种链式触发机制。
优缺点
优点:
- 实现了观察者和目标之间的抽象耦合
- 实现了动态联动(一个操作会引起其它相关的操作)
- 支持广播通信
缺点
- 互为观察者与被观察者间有循环依赖的话,要注意相互通知引起的死循环!
- 可能会引起武威操作,误更新。
本节代码:
https://github.com/coder-pig/DesignPatternsExample/tree/master/14.%20Observer%20Pattern