观察者模式,是一种非常常见的设计模式,在很多系统中随处可见,尤其是涉及到数据状态发生变化需要通知的情况下。
本文以AbstractCursor为例子,展开分析。
观察者模式,Observer Pattern,是一个很实用的模式,本人曾经接触到的各种平台以及曾经参与项目中打印模板解释器中都用到了此模式。

1.意图
定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
热门词汇:依赖 发布-订阅 事件 通知 更新 监听

2.结构


这是一个最简单的观察者模式,目标对象能够添加和删除观察者,当自己某种状态或者行为发生改变时,可通过notify通知注册的观察者进行更新操作。
分 析AbstractCursor的具体情况,我们发现实际工作有时需要对观察者进行统一管理,甚至观察者类型有很多种而又可以分成几个系列,这个时候是要 复杂的多,通过合理的分层这个问题很好解决。下面根据具体情况,我们画出android中abstractCurosr中用到的观察者模式结构图:


观察者分成了两个系列。

3.代码
列举其中相关核心代码如下:

  1. public abstract class AbstractCursor {
  2. //定义管理器
  3. DataSetObservable mDataSetObservable = new DataSetObservable();
  4. ContentObservable mContentObservable = new ContentObservable();
  5. //注册和卸载两类观察者
  6. public void registerContentObserver(ContentObserver observer) {
  7. mContentObservable.registerObserver(observer);
  8. }
  9. public void unregisterContentObserver(ContentObserver observer) {
  10. // cursor will unregister all observers when it close
  11. if (!mClosed) {
  12. mContentObservable.unregisterObserver(observer);
  13. }
  14. }
  15. public void registerDataSetObserver(DataSetObserver observer) {
  16. mDataSetObservable.registerObserver(observer);
  17. }
  18. public void unregisterDataSetObserver(DataSetObserver observer) {
  19. mDataSetObservable.unregisterObserver(observer);
  20. }
  21. //2类通知方法
  22. protected void onChange(boolean selfChange) {
  23. synchronized (mSelfObserverLock) {
  24. mContentObservable.dispatchChange(selfChange);
  25. if (mNotifyUri != null && selfChange) {
  26. mContentResolver.notifyChange(mNotifyUri, mSelfObserver);
  27. }
  28. }
  29. }
  30. protected void notifyDataSetChange() {
  31. mDataSetObservable.notifyChanged();
  32. }
  33. }
 再看看Observable<T>类和DataSetObservable类:
  1. public abstract class Observable<T> {
  2. /**
  3. * 观察者列表
  4. */
  5. protected final ArrayList<T> mObservers = new ArrayList<T>();
  6. public void registerObserver(T observer) {
  7. if (observer == null) {
  8. throw new IllegalArgumentException("The observer is null.");
  9. }
  10. synchronized(mObservers) {
  11. if (mObservers.contains(observer)) {
  12. throw new IllegalStateException("Observer " + observer + " is already registered.");
  13. }
  14. mObservers.add(observer);
  15. }
  16. }
  17. public void unregisterObserver(T observer) {
  18. if (observer == null) {
  19. throw new IllegalArgumentException("The observer is null.");
  20. }
  21. synchronized(mObservers) {
  22. int index = mObservers.indexOf(observer);
  23. if (index == -1) {
  24. throw new IllegalStateException("Observer " + observer + " was not registered.");
  25. }
  26. mObservers.remove(index);
  27. }
  28. }
  29. public void unregisterAll() {
  30. synchronized(mObservers) {
  31. mObservers.clear();
  32. }
  33. }
  34. }

  和

  1. public class DataSetObservable extends Observable<DataSetObserver> {
  2. /**
  3. * 数据发生变化时,通知所有的观察者
  4. */
  5. public void notifyChanged() {
  6. synchronized(mObservers) {
  7. for (DataSetObserver observer : mObservers) {
  8. observer.onChanged();
  9. }
  10. }
  11. }
  12. //... ... (其他方法)
  13. }

  观察者DataSetObserver类是一个抽象类:

  1. public abstract class DataSetObserver {
  2. public void onChanged() {
  3. // Do nothing
  4. }
  5. }

  所以我们具体看它的子类:

  1. public class AlphabetIndexer extends DataSetObserver{
  2. /*
  3. * @hide 被android系统隐藏起来了
  4. */
  5. @Override
  6. public void onChanged() {
  7. //观察到数据变化,观察者做自己该做的事情
  8. super.onChanged();
  9. mAlphaMap.clear();
  10. }
  11. }

  ContentObserver也是类似。

4.效果
(1).行为型模式
(2).目标和观察者间的抽象耦合(经典实现)。
(3).支持广播通信(相信这点android开发者看到后应该有启发吧)。
(4).注意意外的更新,这也是观察者更新进行管理的原因之一。

Android设计模式系列(2)--SDK源码之观察者模式的更多相关文章

  1. Android设计模式系列(3)--SDK源码之单例模式

    单例模式,可以说是GOF的23种设计模式中最简单的一个.这个模式相对于其他几个模式比较独立,它只负责控制自己的实例化数量单一(而不是考虑为用户产生什么样的实例),很有意思,是一个感觉上很干净的模式,本 ...

  2. Android设计模式系列(1)--SDK源码之组合模式

    Android中对组合模式的应用,可谓是泛滥成粥,随处可见,那就是View和ViewGroup类的使用.在android UI设计,几乎所有的widget和布局类都依靠这两个类.组合模式,Compos ...

  3. Android开发系列之系统源码目录

    相信大家对于Google给出的那副经典Android架构图非常的熟悉,从下往上依次是Linux内核层(主要是负责硬件管理调度),HAL层(主要是硬件抽象层),libs层+Runtime,Framewo ...

  4. Android笔记: 查看SDK源码

    Eclipse中设置查看JavaAndroid源码及文档的方法.pdf 经验证方法可行

  5. Android设计模式系列

    http://www.cnblogs.com/qianxudetianxia/category/312863.html Android设计模式系列(12)--SDK源码之生成器模式(建造者模式) 摘要 ...

  6. Android基础之在Eclipes中关联SDK源码和查看SDK源码

    在进行Android应用开发的时候,我们有时候需要查看某个类或接口的源码从而了解如何去使用一个类或者实现一个接口,查看源码有助于我们的学习某个封装的类的底层是如何实现的,这样可以帮助我们掌握类或者接口 ...

  7. 怎样将Android SDK源码 导入到Eclipse中?

    在Eclipse中导入android sdk源码 http://blog.csdn.net/hahahacff/article/details/8590649

  8. eclipse导入java和android sdk源码,帮助文档

    eclipse导入java和android sdk源码,帮助文档 http://blog.csdn.net/ashelyhss/article/details/37993261 JavaDoc集成到E ...

  9. Android 7.1.1系统源码下载、编译、刷机-Nexus 6实战

    想成为一位合格的Android程序员或者一位Android高级工程师是十分有必要知道Android的框架层的工作原理,要知道其工作原理那么就需要阅读Android的源代码. 想要阅读Android的源 ...

随机推荐

  1. ExtJs xtype一览

    标签: extjs xtype 分类: HTML 基本组件: xtype Class 描述 button Ext.Button 按钮 splitbutton Ext.SplitButton 带下拉菜单 ...

  2. ExtJs ComboBox 在IE 下 自动完成功能无效的解决方案

    使用 ComboBox 来作为自动完成的组件,就像google suggestion ,可是在IE下怎么也无法输入字符,是处于不可编辑状态,而firefox和chrome都正常显示.我在2个ExtJs ...

  3. 'NSUnknownKeyException', reason:....etValue:forUndefinedKey:]: this class is not key value coding-compliant for the key

    erminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<MainTableViewControl ...

  4. mogodb优化

    http://snoopyxdy.blog.163.com/blog/static/6011744020157511536993/ http://www.csdn.net/article/2012-1 ...

  5. glob函数的使用

    glob库函数用于Linux文件系统中路径名称的模式匹配,即查找文件系统中指定模式的路径.注意,这不是正则表达式匹配,虽然有些相似,但还是有点差别. glob函数原型       #include & ...

  6. 仿LOL项目开发第一天

    ---恢复内容开始--- 仿LOL项目开发第一天 by---草帽 项目源码研究群:539117825 最近看了一个类似LOL的源码,颇有心得,所以今天呢,我们就来自己开发一个类似于LOL的游戏demo ...

  7. WPF性能调试系列 – 内存监测

    WPF性能调试系列文章: WPF页面渲染优化:Application Timeline WPF页面业务加载优化:Ants Performance Profiler     WPF内存优化:Ants M ...

  8. iOS:判断引导页首次出现、版本更新

    判断引导页首次出现方式: //选择根控制器 +(void)chooseRootViewController{ //初始化Window窗口 [AppDelegate Delegate].window = ...

  9. OpenCV学习(9) 分水岭算法(3)

    本教程我学习一下opencv中分水岭算法的具体实现方式. 原始图像和Mark图像,它们的大小都是32*32,分水岭算法的结果是得到两个连通域的轮廓图. 原始图像:(原始图像必须是3通道图像) Mark ...

  10. php stdClass 的使用

    原文:http://www.php.cn/php-weizijiaocheng-371767.html ------------------------------------------------ ...