设计模式之三:观察者模式

  • 观察者模式
  • 目录介绍
  • 1.观察者模式介绍
  • 2.观察者使用场景
  • 3.观察者UML图解
  • 4.观察者模式简单实现
  • 4.0 举个例子
  • 4.1 观察者代码
  • 4.2 被观察者代码
  • 4.3 测试代码
  • 4.4 思考
  • 5.观察者模式Android源码分析
  • 5.1 先来看看源代码
  • 5.2 观察者从哪里来的,查看setAdapter源代码
  • 5.3 观察者在哪里创建的呢?如何运作
  • 5.4 代码分析
  • 6.观察者模式深入探索
  • 7.EventBus事件总线
  • 7.1 遇到的问题
  • 7.2 目前流行事件总线框架
  • 7.3 源码解读,单独写成博客呢
  • 7.4 使用步骤
  • 8.其他说明
  • 8.1 参考文档:源码设计模式解析

0.本人写的综合案例

1.观察者模式介绍

  • 1.1 最常用的地方是GUI系统、订阅——发布系统等
  • 1.2 重要作用就是解耦,使得它们之间的依赖性更小,甚至做到毫无依赖
  • 1.3 观察者模式又被称作发布/订阅模式,观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己。
  • 1.4 举个例子:
    就拿csdn这个类似于博客的网站来说吧,如果你订阅了或者说关注了一个领域,就能收到这个领域文章的推送,如果没有关注,则不能。是相当于有一个总控制台(被观察者,持有数据源,这里的数据源是我们每个订阅了的人)通知下面的观察者。

2.观察者使用场景

  • 事件多级触发场景
  • 跨系统的消息交换场景,如消息队列,事件总线的处理机制

3.观察者UML图解

  • 3.1 关于UML类图
  • 3.2 角色介绍
    • 抽象主题(Subject):它把所有观察者对象的引用保存到一个聚集里,每个主题都可以有任何数量的观察者。抽象主题提供一个接口,可以增加和删除观察者对象。
    • 具体主题(ConcreteSubject):将有关状态存入具体观察者对象;在具体主题内部状态改变时,给所有登记过的观察者发出通知。
    • 抽象观察者(Observer):为所有的具体观察者定义一个接口,在得到主题通知时更新自己。
    • 具体观察者(ConcreteObserver):实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题状态协调。
  • 3.3 其他说明
    • 1.Subject 和 Observer 是一个一对多的关系,也就是说观察者只要实现 Observer 接口并把自己注册到 Subject 中就能够接收到消息事件;
    • 2.Java API有内置的观察者模式类:java.util.Observable 类和 java.util.Observer 接口,这分别对应着 Subject 和 Observer 的角色;
    • 3.使用 Java API 的观察者模式类,需要注意的是被观察者在调用 notifyObservers() 函数通知观察者之前一定要调用 setChanged() 函数,要不然观察者无法接到通知;
    • 4.使用 Java API 的缺点也很明显,由于 Observable 是一个类,java 只允许单继承的缺点就导致你如果同时想要获取另一个父类的属性时,你只能选择适配器模式或者是内部类的方式,而且由于 setChanged() 函数为 protected 属性,所以你除非继承 Observable 类,否则你根本无法使用该类的属性,这也违背了设计模式的原则:多用组合,少用继承。

4.观察者模式简单实现

  • 4.0 举个例子

    • 就拿csdn这个类似于博客的网站来说吧,如果你订阅了或者说关注了一个领域,就能收到这个领域文章的推送,如果没有关注,则不能。是相当于有一个总控制台(被观察者,持有数据源,这里的数据源是我们每个订阅了的人)通知下面的观察者。
  • 4.1 观察者代码
    • 观察者,也就是你【程序员】,订阅专题的人
      ```
      public class MeObserver implements Observer {

    private String yourName;
    public MeObserver(String yourName){
    this.yourName=yourName;
    }
    @Override
    public void update(Observable o, Object arg) {
    System.out.println("你订阅的"+arg.toString()+"更新了。");
    }
    @Override
    public String toString() {
    return "your name "+yourName;
    }
    }

  • 4.2 被观察者代码
    • 你订阅的简书android领域。被观察者:当他有更新时,所有的观察者都会接收到响应的通知
      ```
      public class MeUser extends Observable {

    private String name;
    private int age;
    private String sex;

    public String getName() {
    return name;
    }

    public void setName(String name) {
    this.name = name;
    setChanged();
    notifyObservers();
    }

    public int getAge() {
    return age;
    }

    public void setAge(int age) {
    this.age = age;
    setChanged();
    notifyObservers();
    }

    public String getSex() {
    return sex;
    }

    public void setSex(String sex) {
    this.sex = sex;
    //setChanged();告知数据改变,通过notifyObservers();发送信号通知观察者。
    setChanged();
    notifyObservers();
    }

    @Override
    public String toString() {
    return "MeUser [name=" + name + ", age=" + age + ", sex=" + sex + "]";
    }
    }

  • 4.3 测试代码
    • 相当于服务器更新通知

      MeUser user=new MeUser();
      MeObserver coder1=new MeObserver("name1");
      MeObserver coder2=new MeObserver("name2");
      MeObserver coder3=new MeObserver("name3");
      user.addObserver(coder1);
      user.addObserver(coder2);
      user.addObserver(coder3);
      user.postNewContentToCoder("contentChanged");
  • 4.4 思考:为什么观察者是实现一个observer接口,而被观察者是继承一个抽象类呢
    • 被观察者写成抽象类的原因是复用,观察者写成接口的原因是降低代码的耦合度,面向接口编程,在原则里就是依赖倒置原则,我们倒着思考,如果这里不是接口,而是一个具体的类,那么,耦合度就相当高了,如果不是观察者注册就无法添加到observable里,就要修改observable的代码

5.观察者模式Android源码分析

  • RecycleView是Android中重要控件,其中adapter刷新数据的adapter.notifyDataSetChanged()就用到了观察者模式
  • 5.1 先来看看源代码

    /*
    * Notify any registered observers that the data set has changed.
    * 通知已登记的数据集已更改的任何观察者。
    *
    * <p>This event does not specify what about the data set has changed, forcing
    * any observers to assume that all existing items and structure may no longer be valid.
    * LayoutManagers will be forced to fully rebind and relayout all visible views.</p>
    * 此事件没有指定数据集发生了什么变化,迫使任何观察者假设所有现有的项和结构可能不再有效。
    * LayoutManagers将不得不完全重新绑定和保护所有可见的视图
    */
    public final void notifyDataSetChanged() {
    mObservable.notifyChanged();
    }
    //然后调用此方法
    public void notifyChanged() {
    // 遍历所有观察者,并且调用它们的onChanged方法
    for (int i = mObservers.size() - 1; i >= 0; i--) {
    mObservers.get(i).onChanged();
    }
    }
  • 5.2 观察者从哪里来的,查看setAdapter源代码
    public void setAdapter(Adapter adapter) {
    // bail out if layout is frozen
    setLayoutFrozen(false);
    setAdapterInternal(adapter, false, true);
    requestLayout();
    }
    private void setAdapterInternal(Adapter adapter, boolean compatibleWithPrevious,boolean removeAndRecycleViews) {
    //如果有adapter,那么先注销对应观察者
    if (mAdapter != null) {
        mAdapter.unregisterAdapterDataObserver(mObserver);
        mAdapter.onDetachedFromRecyclerView(this);
    }
    
    if (!compatibleWithPrevious || removeAndRecycleViews) {
        removeAndRecycleViews();
    }
    //重置
    mAdapterHelper.reset();
    final Adapter oldAdapter = mAdapter;
    mAdapter = adapter;
    if (adapter != null) {//将观察者注册到adapter中
        adapter.registerAdapterDataObserver(mObserver);
        adapter.onAttachedToRecyclerView(this);
    }
    if (mLayout != null) {
        mLayout.onAdapterChanged(oldAdapter, mAdapter);
    }
    
    mRecycler.onAdapterChanged(oldAdapter, mAdapter, compatibleWithPrevious);
    mState.mStructureChanged = true;
    markKnownViewsInvalid();
    }
    
  • **5.3 观察者在哪里创建的呢?如何运作
    //查看源代码,可以知道
    private final RecyclerViewDataObserver mObserver = new RecyclerViewDataObserver();
    //查看onchang方法
    private class RecyclerViewDataObserver extends AdapterDataObserver {
    @Override
    public void onChanged() {
        assertNotInLayoutOrScroll(null);
        mState.mStructureChanged = true;
        setDataSetChangedAfterLayout();
        if (!mAdapterHelper.hasPendingUpdates()) {
            requestLayout();
        }
    }
    }
    void setDataSetChangedAfterLayout() {
    if (mDataSetHasChangedAfterLayout) {
        return;
    }
    mDataSetHasChangedAfterLayout = true;
    //获取adapter中数据的数量
    final int childCount = mChildHelper.getUnfilteredChildCount();
    for (int i = 0; i < childCount; i++) {
        final ViewHolder holder = getChildViewHolderInt(mChildHelper.getUnfilteredChildAt(i));
        if (holder != null && !holder.shouldIgnore()) {
    holder.addFlags(ViewHolder.FLAG_ADAPTER_POSITION_UNKNOWN);
        }
    }
    
    mRecycler.setAdapterPositionsAsUnknown();
    // immediately mark all views as invalid, so prefetched views can be
    // differentiated from views bound to previous data set - both in children, and cache
    markKnownViewsInvalid();
    }
    
  • 5.4 代码分析
  • 在Adapter里面有一个AdapterDataObservable,是被观察者,被观察者必须有三个方法,注册,销毁,通知,这里的注册就是registerAdapterDataObserver,通知就是notify相关的。
  • 在setAdapter的时候,将观察者,也就是RecyclerViewDataObserver注册到AdapterDataObservable里面来维护,观察者里面自然是更新布局。
  • 我们调用notifyDataSetChanged其实就是调用被观察者的notify相关方法

6.观察者模式深入探索

7.EventBus事件总线

  • 7.1 遇到的问题

    • 在Activity与Fragment中通信,需要有对方的引用,会导致耦合性较高。怎么办呢?
    • 想在Activity-B中回调Activity-A的某个函数,但是Activity又不能手动创建对象设置一个listener。该怎么办呢?
    • 如何在service中更新Activity或者fragment的界面呢???
  • 7.2 目前流行事件总线框架
    • EventBus 是异步执行 使用name pattern模式,效率高,但使用不方便
    • Otto 订阅函数不是异步执行 使用注解,使用方便,但效率比不上EventBus
    • AndroidEventBus 是异步执行 订阅函数支持tag,使得事件投递更准确
  • 7.3 源码解读
    • 可以直接看EventBus源码解析文章
  • 7.4 使用步骤
    • 可以直接看EventBus源码解析文章

其他说明

时间: 2024-11-16 06:42:38

设计模式之三:观察者模式的相关文章

PHP设计模式之观察者模式示例介绍

 这篇文章主要介绍了PHP设计模式之观察者模式(Observer)详细介绍和代码实例,需要的朋友可以参考下 [意图]   定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新[GOF95] 又称为发布-订阅(Publish-Subscribe)模式.模型-视图(Model-View)模式.源-监听(Source-Listener)模式.或从属者(Dependents)模式   [观察者模式结构图]       [观察者模式中主要角色]   1.抽

Javascript设计模式之观察者模式的多个实现版本实例

 这篇文章主要介绍了Javascript设计模式之观察者模式的多个实现版本实例,本文给出3种实现版本代码,同时给出了Jquery实现版本,需要的朋友可以参考下     介绍 观察者模式又叫发布订阅模式(Publish/Subscribe),它定义了一种一对多的关系,让多个观察者对象同时监听某一个主题对象,这个主题对象的状态发生变化时就会通知所有的观察者对象,使得它们能够自动更新自己. 使用观察者模式的好处: 1.支持简单的广播通信,自动通知所有已经订阅过的对象. 2.页面载入后目标对象很容易与观

PHP设计模式之观察者模式实例_php实例

首先了解观察者模式的概念:一个对象通过添加一个方法(该方法允许另一个对象,即观察者 注册自己)使本身变得可观察.当可观察的对象更改时,它会将消息发送到已注册的观察者.这些观察者使用该信息执行的操作与可观察的对象无关.结果是对象可以相互对话,而不必了解原因.观察者模式是一种事件系统,意味着这一模式允许某个类观察另一个类的状态,当被观察的类状态发生改变的时候,观察类可以收到通知并且做出相应的动作;观察者模式为您提供了避免组件之间紧密耦. UML结构图: 观察者模式解决的问题 在我们的开发过程中,应该

设计模式之三(工厂方法模式)

原文:设计模式之三(工厂方法模式) 前言 工厂方法模式:定义一个用于创建对象的接口,让子类决定实例化那一个类.工厂方法使一个类的实例化延迟到其子类. 简单工厂模式(http://www.cnblogs.com/aehyok/archive/2013/05/10/3072008.html)的最大优点在于工厂类中包含了必要的逻辑判断,根据客户端的选择条件动态实例化相关的类,对于客户端来说,去除了与具体产品的依赖. 工厂方法模式实现时,客户端需要决定实例化那一个工厂来实现运算类,选择判断的问题还是存在

乐在其中设计模式(C#) - 观察者模式(Observer Pattern)

原文:乐在其中设计模式(C#) - 观察者模式(Observer Pattern)[索引页][源码下载] 乐在其中设计模式(C#) - 观察者模式(Observer Pattern) 作者:webabcd 介绍 定义对象间的一种一对多的依赖关系,以便当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并自动刷新. 示例 有一个Message实体类,某些对象对它的操作有Insert()方法,当发生某些改变的时候,通知所有这些对象并执行Insert()方法. MessageModel using

设计模式之观察者模式(Observable与Observer)

好久没有写博客啦,之前看完了<设计模式之禅>也没有总结一下,现在回忆一下设计模式之观察者模式. 1.什么是观察者模式 简单情形:有A.B.C.D等四个独立的对象,其中B.C.D这三个对象想在A对象发生改变的第一时间知道这种改变,以便做出相应的响应或者对策. 上面的这种情形,就是观察者模式. 当然可以有多个观察者,多个被观察者. 观察者与被观察者也不是对立的,一个对象可以观察其他对象,也可以被其他对象观察. 2.观察者模式的应用 为了更好的理解什么是观察者模式,下面我举一些可能用到该模式的情形或

【设计模式】—— 观察者模式Observer

模式意图 观察者模式,也叫发布/订阅模式,从名字来说就能察觉到它的过程应该是,发布--其他人接受. 这个模式定义了对象之间的一种依赖关系,当一个对象发生变化时,其他的对象收到更新,也发生变化. 模拟我们订阅邮件这个场景,不管我们的邮箱是在登陆还是关闭,邮件都会发送到邮箱里面.只要把自己的邮箱订阅到这个邮件就可以了!这个模式也是这样一个过程. 这个模式代码相对来说比较容易理解,而且应用很广泛. 应用场景 1 当一个模型有几个展现方面,通过修改一个展现,顺便更新其他的.就好比一个网站的有web端,也

设计模式之观察者模式(关于OC中的KVO\KVC\NSNotification)

学习了这么久的设计模式方面的知识,最大的感触就是,设计模式不能脱离语言特性.近段时间所看的两本书籍,<大话设计模式>里面的代码是C#写的,有一些设计模式实现起来也是采用了C#的语言特性(C#的API,抽象类,在OC中是没有抽象类.没有多继承关系),<设计模式之禅>里面的代码是JAVA写的,与OC差距也是比较大. 但是我想,这些都不是问题,学习设计模式主要学习的是其中的思想,并将之改造成自己所熟悉语言的模式,大同小异.所需要注意的是,在学习的过程中,将之与语言结合起来,多思考.多实践

JavaScript设计模式之观察者模式

设计模式(Design Pattern)对于软件开发来说其重要性不言而喻,代码可复用.可维护.可扩展一直都是软件工程中的追求!对于我一个学javascript的人来说,理解设计模式似乎有些困难,对仅切图.做少量交互效果的FE甚至可能不会用到,但是当你开始使用Angular/Backbone等框架的时候,就无法避免设计模式.MVC/MVVM这些东西了(反正我是伤脑筋). 我学设计模式是刚开始接触编程大概三个月的时候,看一本书<大话设计模式>,里面用C#语言来写,我很无语,因为强类型的编程语言对于