Android中的设计模式-观察者模式

沛公军霸上,未得与项羽相见。沛公左司马曹无伤使人言于项羽曰:“沛公欲王关中,使子婴为相,珍宝尽有之。”项羽大怒曰:“旦日飨士卒,为击破沛公军!”……项伯乃夜驰之沛公军。——《史记·项羽本纪》
曹无伤是项羽安插在刘邦身旁的“卧底”,也就是项羽向刘邦注册的一个“观察者”,在“主题”刘邦状态改变时:“沛公欲王关中”,向“订购者”项羽发送通知:“使人言于项羽”。
不过,虽然鸿门宴上杀机重重,但刘邦最后还是有惊无险,完身而退,因为在项羽那儿也有他的金牌“卧底”——项伯,来给他通风报信。项伯是“观察者”,在“主题”项羽状态改变时:“大怒,为击破沛公军”,向“订购者”刘邦发送通知:“夜驰之沛公军”。
真没想到,历史上那场著名的饭局和危机公关,居然是使用观察者模式来引发和解决的。

观察者模式有时也被称作发布/订阅模式、Listener模式。

定义对象间一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。

结构图如下:
这里写图片描述
我们知道,当一个对象需要向别的对象发送通知时,可以调用别的对象的方法接口,这样自己一方的信息就通知过去了,这是常规的方式,是正向调用,也就是它要依赖于别的对象。那么,如果另有新的对象也需要被通知时怎么办?只能在发出通知的对象中修改代码,来通知新的对象,可见,随着新对象的加入,对旧的对象产生了变化,这是典型的面向过程编程,不是一个好的方案。

如何才能封装这种变化呢?面向接口编程是不二法门。我们考虑采用类似于前面介绍的策略模式方案,也就是让Subject作为Context角色,是使用策略对象的,当新建一个对象Observer时,把它看作是新提供了一个策略对象,Observer是独立变化的,需要新增加具体Observer类时,都不会修改Subject类。Subject不再依赖于具体Observer,而是依赖于它们的接口基类,这是依赖倒置原则,解耦了。当有新的具体Observer对象时,Subject没有变化。这样当新建一个Observer对象,就有相应的场景类把它添加到Subject中去,Subject不知道发生了变化。从职责的角度看Subject通知Observer发生了事件,让别人实现功能,Subject向这些订购者广播通知,就像是一些Observer对象在Subject中观察发生变化了没有,所以叫观察者模式。从实现上来说,具体Observer要向Subject进行注册,是Observer依赖于Subject,对Subject而言,它反向依赖于Observer,Observer的变化就不会影响到Subject,核心是反向调用,如果用一个关键字描述的话,就是回调

观察者模式是Android系统中很常见的一种设计模式,它也是实现IOC模式的一种方式(另一种是模板方法模式)。在Android中View响应事件的框架就是观察者模式,只不过是观察者只有一个罢了,那些OnXXXListener接口对象都是观察者,可能有的朋友有疑问了,它们的类结构图和观察者的类结构图不一样啊?应用设计模式,不一定非要严格按照模式的标准结构图来实现,关键是要理解里面的原理,没必要生搬硬套。

观察者模式的结构图和策略模式类似,比如Subject是Context角色,Observer是策略角色,Subject委托引用Observer,它们可以独立变化。当Subject需要发送通知时,要调用Observer,而具体的Observer是由场景类选择的,Subject没有变化。从职责上来说,Subject并不像策略模式那样使用Observer来扩展自己的功能,而是通知Observer发生了事件,让别人实现功能,即Subject向这些订购者广播了通知。

强调几个注意事项:

  1. 向Subject中添加观察者时,注意线程安全,通常可以使用CopyOnWriteArrayList来保存观察者,简单而且线程安全。
  2. 注意内存泄漏,当一个观察者不再需要Subject发送通知时,要从Subject中移除相应的观察者对象。
  3. Observer有可能在被观察者调用运行时,和实现Observer的不在同一个线程,注意线程安全。
  4. 观察者可以既是观察者又是被观察者,这种情况下,要注意会出现调用链死循环。
  5. Subject发送的消息有可能被观察者修改,对排在后面的观察者有影响,个人认为最好不要修改传过来的参数对象,因为可能还有别的观察者在观察,如果改变了参数对象,可能发生意外,修改时要谨慎对待。
  6. 注意效率,如果一个观察者阻塞了,后面的观察者都跟着被阻塞,可以考虑使用异步。例如,当使用OnClickListener响应View事件时,如果要从数据库获取数据,一般要使用了异步方式,防止事件太长阻塞了UI线程的其它事件的处理。
  7. 用于观察者对象不固定,或者会发生变化时的场景,如果观察者不会发生变化,就不要使用该模式,否则适得其反,直接使用正向调用就行。

该模式在Java和Android开发中非常常见,不再举例了,大家非常熟练,下面是一些常见的观察者模式模块:

  1. Java提供了相关的类和接口:Observable与Observer,在开发实践中可以直接使用。
  2. FileObserver:Android系统提供的一种监控文件系统变化通知机制,可以用来监听文件访问、创建、修改、删除、移动等操作。
  3. ContentObserver:观察(捕捉)特定 Uri 引起的数据库的变化, 继而做一些相应的处理。
  4. Android相关模块中各种onXXXXListener接口。

猜你喜欢

转载自blog.csdn.net/moter/article/details/80322484