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

简介:
  • 观察者模式
  • 目录介绍
  • 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类图
    Image.png
  • 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源码解析文章

其他说明

目录
相关文章
|
7天前
|
设计模式 监控 Java
Kotlin教程笔记(52) - 改良设计模式 - 观察者模式
Kotlin教程笔记(52) - 改良设计模式 - 观察者模式
|
27天前
|
设计模式 传感器
【设计模式】观察者模式(定义 | 特点 | Demo入门讲解)
【设计模式】观察者模式(定义 | 特点 | Demo入门讲解)
34 0
|
3天前
|
设计模式 监控 Java
Kotlin教程笔记(52) - 改良设计模式 - 观察者模式
Kotlin教程笔记(52) - 改良设计模式 - 观察者模式
12 3
|
14天前
|
设计模式 监控 Java
Kotlin教程笔记(52) - 改良设计模式 - 观察者模式
Kotlin教程笔记(52) - 改良设计模式 - 观察者模式
32 9
|
13天前
|
设计模式 监控 Java
Kotlin教程笔记(52) - 改良设计模式 - 观察者模式
Kotlin教程笔记(52) - 改良设计模式 - 观察者模式
26 2
|
22天前
|
设计模式 监控 UED
设计模式之观察者模式
【10月更文挑战第12天】 观察者模式是一种行为型设计模式,定义了一对多的依赖关系,当一个对象状态改变时,所有依赖它的对象都会自动更新。主要由主题(被观察者)和观察者组成,实现对象间的松耦合,广泛应用于用户界面、事件驱动系统和数据监控等领域。
|
24天前
|
设计模式 监控 Java
Kotlin教程笔记(52) - 改良设计模式 - 观察者模式
本教程详细讲解Kotlin语法,适合深入学习。对于快速掌握Kotlin,推荐“简洁”系列教程。本文特别介绍了观察者模式,包括使用Java API和Kotlin委托属性(如Delegates.observable)实现的方法,旨在帮助开发者更高效地实现和优化观察者模式的应用。
31 3
|
2月前
|
设计模式 Java 关系型数据库
设计模式——观察者模式
观察者模式介绍、观察者模式优化天气预报案例、JDK 的Observable类和Observer类
设计模式——观察者模式
|
27天前
|
设计模式 监控 Java
Kotlin教程笔记(52) - 改良设计模式 - 观察者模式
Kotlin教程笔记(52) - 改良设计模式 - 观察者模式
28 0
|
3月前
|
设计模式 存储 前端开发
【十四】设计模式~~~行为型模式~~~观察者模式(Java)
文章详细介绍了观察者模式(Observer Pattern),这是一种对象行为型模式,用于建立对象之间的一对多依赖关系。当一个对象状态发生改变时,所有依赖于它的对象都会得到通知并自动更新。文中通过交通信号灯与汽车的案例以及多人联机对战游戏的设计方案,阐述了观察者模式的动机和应用场景。接着,文章介绍了观察者模式的结构、角色、优点、缺点以及适用情况,并通过代码示例展示了如何在Java中实现观察者模式。此外,还探讨了观察者模式在MVC架构中的应用以及Java中对观察者模式的支持。
【十四】设计模式~~~行为型模式~~~观察者模式(Java)

热门文章

最新文章

  • 1
    《手把手教你》系列基础篇(九十四)-java+ selenium自动化测试-框架设计基础-POM设计模式实现-下篇(详解教程)
    44
  • 2
    C++一分钟之-C++中的设计模式:单例模式
    51
  • 3
    《手把手教你》系列基础篇(九十三)-java+ selenium自动化测试-框架设计基础-POM设计模式实现-上篇(详解教程)
    36
  • 4
    《手把手教你》系列基础篇(九十二)-java+ selenium自动化测试-框架设计基础-POM设计模式简介(详解教程)
    59
  • 5
    Java面试题:结合设计模式与并发工具包实现高效缓存;多线程与内存管理优化实践;并发框架与设计模式在复杂系统中的应用
    54
  • 6
    Java面试题:设计模式在并发编程中的创新应用,Java内存管理与多线程工具类的综合应用,Java并发工具包与并发框架的创新应用
    39
  • 7
    Java面试题:如何使用设计模式优化多线程环境下的资源管理?Java内存模型与并发工具类的协同工作,描述ForkJoinPool的工作机制,并解释其在并行计算中的优势。如何根据任务特性调整线程池参数
    49
  • 8
    Java面试题:请列举三种常用的设计模式,并分别给出在Java中的应用场景?请分析Java内存管理中的主要问题,并提出相应的优化策略?请简述Java多线程编程中的常见问题,并给出解决方案
    102
  • 9
    Java面试题:设计模式如单例模式、工厂模式、观察者模式等在多线程环境下线程安全问题,Java内存模型定义了线程如何与内存交互,包括原子性、可见性、有序性,并发框架提供了更高层次的并发任务处理能力
    74
  • 10
    Go语言设计模式:使用Option模式简化类的初始化
    71