一、介绍

观察者模式是一个使用率非常高的模式,它最常用的地方是GUI系统、订阅——发布系统。因为这个模式的一个重要作用就是解耦,将被观察者和观察者解耦,使得它们之间的依赖性更小,甚至做到毫无依赖。以GUI系统来说,应用的UI具有易变性,尤其是前期随着业务的改变或者产品的需求修改,应用界面也会经常性变化,但是业务逻辑基本变化不大,此时,GUI系统需要一套机制来应对这种情况,使得UI层与具体的业务逻辑解耦,观察者模式此时就派上用场了。

二、定义

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

三、使用场景

  • 关联行为场景,需要注意的是,关联行为是可拆分的,而不是”组合“关系。

  • 事件多级触发场景。

  • 跨系统的消息交换场景,如消息队列、事件总线的处理机制。

四、观察者模式的UML类图

UML类图:

角色介绍:

  • Subject:抽象主题,也就是被观察者(Observable)的角色,抽象主题角色把所有观察者对象的引用保存到一个聚集里,每个主题都可以有任何数量的观察者。抽象主题提供一个接口,可以增加和删除观察者对象。

  • ConcreteSubject:具体主题,该角色将有关状态存入具体观察者对象,在具体主题的内部状态发生改变时,给所有注册过的观察者发出通知,具体主题角色又叫做具体被观察者(ConcreteObservable)角色。

  • Observer:抽象观察者,该角色是观察者的抽象类,它定义了一个更新接口,使得在得到主题的更改通知时更新自己。

  • ConcreteObserver:具体的观察者,该角色实现抽象观察者角色所定义的更新接口,以便主题的状态发生改变化时更新自身的状态。

五、简单实现

这里举一个追剧的例子,平常为了不错过最新的电视剧我们会订阅或关注这个电视剧,当电视剧更新后会第一时间推送给我们,下来就简单实现一下。

抽象观察者类:

/***  抽象观察者类,为所有具体观察者定义一个接口,在得到通知时更新自己*/
public interface Observer {/***  有更新*  *  @param message 消息*/public void update(String message);}

抽象被观察者类:

/*** 抽象被观察者类*/
public interface Observable {/*** 推送消息* * @param message 内容*/void push(String message);/*** 订阅* * @param observer 订阅者*/void register(Observer observer);
}

具体的观察者类:

/*** 具体的观察者类,也就是订阅者*/
public class User implements Observer {@Overridepublic void update(String message) {System.out.println(name + "," + message + "更新了!");}// 订阅者的名字private String name;public User(String name) {this.name = name;}
}

具体的被观察者类:

/***  具体的被观察者类,也就是订阅的节目*/
public class Teleplay implements Observable{private List<Observer> list = new ArrayList<Observer>();//储存订阅者@Overridepublic void push(String message) {for(Observer observer:list){observer.update(message);}}@Overridepublic void register(Observer observer) {list.add(observer);}}

实现:

public class Client {public static void main(String[] args) {//被观察者,这里就是用户订阅的电视剧Teleplay teleplay = new Teleplay();//观察者,这里就是订阅用户User user1 = new User("小明");User user2 = new User("小光");User user3 = new User("小兰");//订阅teleplay.register(user1);teleplay.register(user2);teleplay.register(user3);//推送新消息teleplay.push("xxx电视剧");}
}

结果:

小明,xxx电视剧更新了!
小光,xxx电视剧更新了!
小兰,xxx电视剧更新了!

由上面的代码可以看出实现了一对多的消息推送,推送消息都是依赖Observer和Observable这些抽象类,而User和Teleplay完全没有耦合,保证了订阅系统的灵活性和可扩展性。

六、Android源码中的观察者模式

1、BaseAdapter

BaseAdapter我相信大家都不陌生,在ListView的适配器中我们都是继承它。下面来简单分析分析。

BaseAdapter 部分代码:

public abstract class BaseAdapter implements ListAdapter, SpinnerAdapter {//数据集观察者private final DataSetObservable mDataSetObservable = new DataSetObservable();public boolean hasStableIds() {return false;}public void registerDataSetObserver(DataSetObserver observer) {mDataSetObservable.registerObserver(observer);}public void unregisterDataSetObserver(DataSetObserver observer) {mDataSetObservable.unregisterObserver(observer);}/*** 当数据集变化时,通知所有观察者*/public void notifyDataSetChanged() {mDataSetObservable.notifyChanged();}
}

看看mDataSetObservable.notifyChanged()方法:

public class DataSetObservable extends Observable<DataSetObserver> {/*** Invokes {@link DataSetObserver#onChanged} on each observer.* Called when the contents of the data set have changed.  The recipient* will obtain the new contents the next time it queries the data set.*/public void notifyChanged() {synchronized(mObservers) {// since onChanged() is implemented by the app, it could do anything, including// removing itself from {@link mObservers} - and that could cause problems if// an iterator is used on the ArrayList {@link mObservers}.// to avoid such problems, just march thru the list in the reverse order.for (int i = mObservers.size() - 1; i >= 0; i--) {mObservers.get(i).onChanged();}}}
}

可以看出在mDataSetObservable.notifyChanged()中遍历所有观察者,并调用他们的onChanged(),从而告知观察者发生了什么。

那么观察者怎么来的,那就是setAdapter方法,代码如下:

    @Overridepublic void setAdapter(ListAdapter adapter) {if (mAdapter != null && mDataSetObserver != null) {mAdapter.unregisterDataSetObserver(mDataSetObserver);}resetList();mRecycler.clear();if (mHeaderViewInfos.size() > 0|| mFooterViewInfos.size() > 0) {mAdapter = new HeaderViewListAdapter(mHeaderViewInfos, mFooterViewInfos, adapter);} else {mAdapter = adapter;}mOldSelectedPosition = INVALID_POSITION;mOldSelectedRowId = INVALID_ROW_ID;// AbsListView#setAdapter will update choice mode states.super.setAdapter(adapter);if (mAdapter != null) {mAreAllItemsSelectable = mAdapter.areAllItemsEnabled();mOldItemCount = mItemCount;mItemCount = mAdapter.getCount();checkFocus();mDataSetObserver = new AdapterDataSetObserver();mAdapter.registerDataSetObserver(mDataSetObserver);//注册观察者......省略}}

AdapterDataSetObserver定义在ListView的父类AbsListView中,是一个数据集观察者,代码:

class AdapterDataSetObserver extends AdapterView<ListAdapter>.AdapterDataSetObserver {@Overridepublic void onChanged() {super.onChanged();if (mFastScroller != null) {mFastScroller.onSectionsChanged();}}@Overridepublic void onInvalidated() {super.onInvalidated();if (mFastScroller != null) {mFastScroller.onSectionsChanged();}}
}

它由继承自AbsListView的父类AdapterView的AdapterDataSetObserver, 代码如下 :

class AdapterDataSetObserver extends DataSetObserver {private Parcelable mInstanceState = null;// 上文有说道,调用Adapter的notifyDataSetChanged的时候会调用所有观察者的onChanged方法,核心实现就在这里@Overridepublic void onChanged() {mDataChanged = true;mOldItemCount = mItemCount;// 获取Adapter中数据的数量mItemCount = getAdapter().getCount();// Detect the case where a cursor that was previously invalidated has// been repopulated with new data.if (AdapterView.this.getAdapter().hasStableIds() && mInstanceState != null&& mOldItemCount == 0 && mItemCount > 0) {AdapterView.this.onRestoreInstanceState(mInstanceState);mInstanceState = null;} else {rememberSyncState();}checkFocus();// 重新布局ListView、GridView等AdapterView组件requestLayout();}// 代码省略public void clearSavedState() {mInstanceState = null;}
}

当ListView的数据发生变化时,调用Adapter的notifyDataSetChanged函数,这个函数又会调用DataSetObservable的notifyChanged函数,这个函数会调用所有观察者 (AdapterDataSetObserver) 的onChanged方法。这就是一个观察者模式!

七、总结

优点:

  • 观察者和被观察者之间是抽象耦合,应对业务变化。

  • 增强系统的灵活性和可扩展性。

缺点:

  • 在应用观察者模式时需要考虑一下开发效率和运行效率的问题,程序中包括一个被观察者、多个观察者,开发、调试等内容会比较复杂,而且在Java中消息的通知一般是顺序执行,那么一个观察者卡顿,会影响整体的执行效率,在这种情况下,一般会采用异步实现。

Android设计模式之——观察者模式相关推荐

  1. Android设计模式之观察者模式在项目中的实际使用总结

    前言 观察者模式在Android开发中使用频率非常高,最常用的地方如订阅–发布系统,类似微信公众号用户订阅和接收消息的场景,因为这个模式最重要的功能就是解耦,将被观察者和观察者解耦,使得它们之间的依赖 ...

  2. 设计模式:观察者模式--Observer

    一.什么是观察者模式 1.生活中的观察者模式 1.警察抓小偷 在现实生活中,警察抓小偷是一个典型的观察者模式「这以一个惯犯在街道逛街然后被抓为例子」,这里小偷就是被观察者,各个干警就是观察者,干警时时 ...

  3. Android设计模式——单例模式(Singleton)

    二十三种设计模式分为三大类: 创建型模式,共五种:工厂方法模式.抽象工厂模式.单例模式.建造者模式.原型模式. 结构型模式,共七种:适配器模式.装饰器模式.代理模式.外观模式.桥接模式.组合模式.享元 ...

  4. Android—设计模式原则及常见的设计模式

    设计模式六大原则: 单一职责原则:实现类要职责单一,类之间不相互影响. 里氏替换原则:不要破坏继承体系,共享的父类方法应该保持不变,不能被子类重新定义.我们应该将父类定义为抽象类,并定义抽象方法. 依 ...

  5. java/android 设计模式学习笔记目录

    其实很早就想开始总结设计模式了,无奈刚刚换完工作,工作太忙,平时周末也太懒,难得提起精神写一点,估计时间会花的很长,不过还是自己加油吧~~. 学习笔记,顾名思义,其实就是我在平时看书,工作的笔记而已, ...

  6. Android设计模式

    android开发中使用到的一些设计者模式-  http://blog.csdn.net/xiangzhihong8/article/details/28593827 引用: http://m.blo ...

  7. Android设计模式与应用场景

    文章目录 Android 设计模式 1.设计模式的分类 1.1 创建型模式(5种) [单例模式] : [抽象工厂模式]: [工厂方法模式]: [原型模式]: [建造者模式]: 1.2 结构型模式(七种 ...

  8. java/android 设计模式学习笔记(1)--- 单例模式

    前段时间公司一些同事在讨论单例模式(我是最渣的一个,都插不上嘴 T__T ),这个模式使用的频率很高,也可能是很多人最熟悉的设计模式,当然单例模式也算是最简单的设计模式之一吧,简单归简单,但是在实际使 ...

  9. java 观察者模式_图解Java设计模式之观察者模式

    图解Java设计模式之观察者模式 天气预报项目需求 天气预报设计方案 1 - 普通方案 观察者模式(Observer)原理 观察者模式解决天气预报需求 观察者模式在JDK应用的源码分析 天气预报项目需 ...

最新文章

  1. Handler 基本用法--线程间传值
  2. ArcEngine 添加字段
  3. 剑指offer-数组中的重复的数字-p39
  4. DIY小能手|别买电动滑板车了,咱做一台吧
  5. onedrive电脑手机不同步_免费的手机电脑同步便签软件怎么找?求帮忙推荐
  6. 风变编程python第一关_风变编程【学习笔记】,第8关学习心得及代码扩展
  7. Lecture 1:强化学习简介
  8. Atitiit java通过Exchange协议同步note 记事本 目录 1.1.1. 使用EWS(Exchange Web Service)协议读取邮件、发送邮件 1 最新问题 1 热门问题 1
  9. 荣之联:生物云仅仅是开始
  10. 一键搭建Ubuntu开发环境
  11. 实习生到公司第一天应该怎么快速上手
  12. 使用ultraiso安装Ubuntu 18.04系统
  13. 1984年高考数学试题。
  14. fluent-bit代替filebeat实战(smartgate、nginx)
  15. 什么是(flex)弹性盒子主轴和侧轴
  16. 伪元素进度条_使用HTML5进度元素
  17. cass怎么把块打散命令_CAD中炸开命令是什么
  18. SOA协议DDS和Some/IP对比
  19. “打印机故障”,我的解决方案
  20. Spring5知识点综合笔记

热门文章

  1. visual studio 没有属性页_驯龙物语10月14日更新|新增快捷购买页签
  2. 【转】国密加密算法SM系列的C#实现方法
  3. 14工厂方法模式(Factory Method)
  4. usb接口供电不足_AMD RX 6000 系列显卡配备USB-C 接口,支持外接供电
  5. Python3 爬虫学习笔记 C12【验证码对抗系列 — 图形验证码】
  6. REST风格笔记【简介篇】
  7. 简易有WEB文件服务器,Python实现简易版的Web服务器(推荐).pdf
  8. 【HDU - 5965】扫雷(dp)
  9. 【HDU - 3172】Virtual Friends(带权并查集--权为集合元素个数)
  10. 华为nova 7 se鸿蒙,荣耀v40和华为Nova7Pro哪个好-参数对比-更值得入手