Android开发模式之观察者模式

article/2025/9/24 15:51:03

  

目录

一、定义

1.观察者模式

2.UML类图

3.观察者模式中的角色

二、使用场景

三、简单实现

四、观察者模式在java.util包中的应用

五、观察者模式在Button中的应用

六、观察者模式在ListView中的应用

七、观察者模式的优缺点

观察者模式的优点

观察者模式的缺点


一、定义

1.观察者模式

        定义对象一种一对多的依赖关系,使得当一个对象改变状态的时候,所有依赖它的对象都会得到通知并自动更新。观察者模式是一种使用频率非常高的设计模式,最常用的地方就是订阅-发布系统。

2.UML类图

3.观察者模式中的角色

  • Subject(抽象主题): 又叫抽象被观察者,把所有的观察者对象引用保存到一个集合里,每个主题都可以由任何数量的观察者,抽象主题提供一个接口,可以增加和删除观察者对象。
  • ConcreteSubject(具体主题):又叫具体被观察者,将有关的状态存入具体观察者对象,在内部状态改变时,给所有的登记过的观察者发出通知。
  • Observer(抽象观察者):为所有的观察者定义一个接口,在收到主题通知时进行更新。
  • ConcrereObserver(具体观察者):实现抽象观察者定义的更新接口,在得知主题更改通知时更新自身的状态。

二、使用场景

  • 当一个对象的数据更新了需要通知其他对象,但是又不希望和被通知的对象形成耦合;
  • 当一个对象数据更新了,这个对象需要让其他对象也更新数据但是不知道有多少个对象需要更新。
  • 跨系统的消息交换场景,如消息队列、事件总线的处理机制。

三、简单实现

1.被观察者抽象类

public interface Observable<T> {//绑定观察者void addObserver(Observer observer);//移除观察者void removeObserver(Observer observer);//被观察者发出了改变void notifyObservers(String message);
}

2.被观察者实现类

public class ServerObservable implements Observable<String>{private List<Observer> observers = new ArrayList<>();private String message;@Overridepublic void addObserver(Observer observer) {//添加观察者observers.add(observer);}@Overridepublic void removeObserver(Observer observer) {//删除观察者observers.remove(observer);} @Overridepublic void notifyObservers(String message) {//通知观察者有更新的数据for (Observer observer:observers){observer.update(message);}}}

 3.观察者抽象类

public interface Observer {//被观察者改变接受消息,做响应void update(String message);
}

4.观察者实现类

public class User implements Observer{String info;public User(String s) {info = s;}//用于更新数据@Overridepublic void update(String message) {System.out.println(info + message);}
}

5.测试代码

    //创建观察者    User user1 = new User("第一位观察者");User user2 = new User("第二位观察者");User user3 = new User("第三位观察者");//创建被观察者ServerObservable observable = new ServerObservable();observable.add(user1);observable.add(user2);observable.add(user3);//通知更新observable.notifyObservers("需要更新数据");

运行,从结果看当被观察者发出更新数据的通知后所有注册的观察者都会立刻响应到:

四、观察者模式在java.util包中的应用

观察者模式在JDK中就有典型应用,比如java.util.Observable和java.util.Observer类。在使用时,被观察者需要继承java.util.Observable类,观察者需要实现java.util.Observer接口。下面通过一个简单的Demo看一下如何使用JDK中的观察者模式,UML图如下。

 观察者Student的代码

import java.util.Observable;
import java.util.Observer;public class Student implements Observer {private String name;public Student(String name) {this.name = name;}@Overridepublic void update(Observable o, Object arg) {System.out.println(name + (String)arg);}
}

被观察者Teacher的代码

import java.util.Observable;public class Teacher extends Observable {public void publishMessage(String message) {// mark as value changedsetChanged();// trigger notificationnotifyObservers(message);}
}

输出结果如下:

JDK中的Observable基类和Observer接口为我们的简单使用观察者模式提供了方便,但它有一个非常明显的缺点:被观察者Teacher需要继承Observable这个基类,但是如果Teacher已经继承其他的类就不能同时再继承Observable类。解决这个矛盾的思路有两种:一是自定义观察者模式,将add、delete、notify等方法写进Teacher类;二是使用代理模式,在Teacher中维护一个Observable类的对象,并且实现同名的方法。

五、观察者模式在Button中的应用

在Android中我们遇到的最常见的观察者模式就是各种控件的监听。

 //注册观察者button.setOnClickListener(new View.OnClickListener() {//观察者实现类@Overridepublic void onClick(View view) {}});

在这段代码中,Button就是主题也就是被观察者,通过new出的View.OnClickListenerd对象就是具体的观察者;onClickListener就是抽象的观察者接口;最后通过setOnClickListener把观察者注册到被观察者中,源码如下:

//在单击视图时调用的回调的接口定义。public interface OnClickListener {//在单击视图时调用。void onClick(View v);}
//注册观察者 
public void setOnClickListener(@Nullable OnClickListener l) {if (!isClickable()) {setClickable(true);}getListenerInfo().mOnClickListener = l;}//执行点击事件
public boolean performClick() {// We still need to call this method to handle the cases where performClick() was called// externally, instead of through performClickInternal()notifyAutofillManagerOnClick();final boolean result;final ListenerInfo li = mListenerInfo;if (li != null && li.mOnClickListener != null) {playSoundEffect(SoundEffectConstants.CLICK);//调用观察者执行onClickli.mOnClickListener.onClick(this);result = true;} else {result = false;}sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);notifyEnterOrExitForAutoFillIfNeeded(true);return result;}

六、观察者模式在ListView中的应用

在使用ListView时,如果数据改变了需要调用setDataSetChanged()方法来通知ListView更新UI。换一种说法,ListView的UI是观察者,ListView对应的adapter中的数据就是被观察者。它的实现方式就是注册一个观察者到adapter中,以实现监听adapter的数据变化的目的。

 首先看一下listView.setAdapter(adapter);在这个方法中ListView会创建一个

AdapterDataSetObserver类的观察者并且调用adapter的registerDataSetObserver()。

  @Overridepublic void setAdapter(ListAdapter adapter) {//首先确保移除了所有的观察者if (mAdapter != null && mDataSetObserver != null) {mAdapter.unregisterDataSetObserver(mDataSetObserver);}.....if (mAdapter != null) {....//创建AdapterDataSetObserver观察者mDataSetObserver = new AdapterDataSetObserver();//将观察者注册到adaptermAdapter.registerDataSetObserver(mDataSetObserver);....}}
继续看Adapter的registerDataSetObserver方法,发现最终的结果就是把观察者注册到DataSetObservable这个发布者里。
public abstract class BaseAdapter implements ListAdapter, SpinnerAdapter {@UnsupportedAppUsage//被观察者private final DataSetObservable mDataSetObservable = new DataSetObservable();public void registerDataSetObserver(DataSetObserver observer) {//注册观察者mDataSetObservable.registerObserver(observer);}public void unregisterDataSetObserver(DataSetObserver observer) {//移除mDataSetObservable.unregisterObserver(observer);}
...
}
DataSetObservable继承于android.database.Observable,在DataSetObservable中实现了notifyChanged()方法。
package android.database;public class DataSetObservable extends Observable<DataSetObserver> {public void notifyChanged() {synchronized(mObservers) {//通知所有的观察者,调用onChangedfor (int i = mObservers.size() - 1; i >= 0; i--) {mObservers.get(i).onChanged();}}}public void notifyInvalidated() {synchronized (mObservers) {for (int i = mObservers.size() - 1; i >= 0; i--) {mObservers.get(i).onInvalidated();}}}
}

现在我们看一下adapter.notifyDataSetChanged(),其实就是调用了被观察者的notifyChanged()通知观察者onChanged刷新UI。

   public abstract class BaseAdapter implements ListAdapter, SpinnerAdapter {public void notifyDataSetChanged() {mDataSetObservable.notifyChanged();}
}

七、观察者模式的优缺点

观察者模式的优点

解除观察值与主题之间的耦合,让耦合的双方都依赖于抽象,而不是依赖于具体。从而使各自的变化不会影响另一边的变化。

易于扩展,对于同一主题新增观察者时无需修改原有的代码。

观察者模式的缺点

1、依赖关系并未完全解除,抽象主题依然依赖抽象观察者。

2、使用观察者模式需要考虑开发效率和运行效率的问题,程序中包含一个被观察者、多个观察者,开发、调试等会比较复杂,而且java中消息的通知是顺序执行的,如果一个观察者卡顿,会影响整体的执行效率。

3、可能会引起多余的数据通知。

参考资源

Android 源码中的观察者模式 - 掘金 (juejin.cn)

Android设计模式03-观察者模式 - 简书 (jianshu.com)

 


http://chatgpt.dhexx.cn/article/RclD99WO.shtml

相关文章

java设计模式-观察者模式

观察者模式介绍&#xff1a; 观察者模式&#xff08;有时又被称为发布/订阅模式&#xff09;是软件设计模式的一种。在此种模式中&#xff0c;一个目标对象管理所有相依于它的观察者对象&#xff0c;并且在它本身的状态改变时主动发出通知。这通常透过呼叫各观察者所提供的方法…

观察者模式(Observer) 简介

一, 观察者模式(Observer) 的定义 观察者模式: 定义了一种 1对多 的依赖关系, 让多个观察者对象同时监听1个主题对象. 这个主题对象在状态发生变化时, 会通知所有的观察者对象, 使它们能够同时更新自己. 稍微解释一下 这个1 对多 的依赖关系. 1对多 这个关键词我们常常在DB …

观察者模式

第23章 观察者模式 一、观察者模式的基本介绍 观察者模式(Observer Pattern)&#xff1a;定义对象间的一种一对多依赖关系&#xff0c;使得每当一个对象状态发生改变时&#xff0c;其相关依赖对象皆得到通知并被自动更新。 观察者模式又叫做发布-订阅&#xff08;Publish/Subsc…

观察者模式(Observer Pattern)

一、什么是观察者模式 观察者模式是一种对象行为模式。它定义对象间的一种一对多的依赖关系&#xff0c;当一个对象(目标对象)的状态发生改变时&#xff0c;所有依赖于它的对象(观察对象)都得到通知并被自动更新。特点&#xff1a;被观察者和观察者一般是一对多的关系&#xf…

设计模式之观察者模式详解(附应用举例实现)

文章目录 1 观察者模式介绍2 观察者模式详解2.1 观察者模式结构2.2 观察者模式实现2.3 观察者模式应用举例 3 观察者模式与MVC 1 观察者模式介绍 “红灯停&#xff0c;绿灯行”。在这个过程中&#xff0c;交通信号灯是汽车的观察目标&#xff0c;而汽车则是观察者。随着交通信…

23种设计模式——观察者模式

目录 观察者模式&#xff08;Observer&#xff09; 理解 UML图 优缺点 观察者模式在各语言中的支持 Java C# 实例 小丑表演 办公室摸鱼 投资者与股票 观察者模式&#xff08;Observer&#xff09; 本质&#xff1a;触发联动 目标对象变化时&#xff0c;会通知所有登…

设计模式(五)观察者模式

相关文章 设计模式系列 1.观察者模式模式简介 定义 观察者模式&#xff08;又被称为发布-订阅&#xff08;Publish/Subscribe&#xff09;模式&#xff0c;属于行为型模式的一种&#xff0c;它定义了一种一对多的依赖关系&#xff0c;让多个观察者对象同时监听某一个主题对…

Win64 驱动内核编程-28.枚举消息钩子

枚举消息钩子 简单粘贴点百度的解释&#xff0c;科普下消息钩子&#xff1a; 钩子是WINDOWS中消息处理机制的一个要点&#xff0c;通过安装各种钩子&#xff0c;应用程序能够设置相应的子例程来监视系统里的消息传递以及在这些消息到达目标窗口程序之前处理它们。 钩子的种类很…

Anti 消息钩子注入

MSDN上对消息钩子的描述&#xff1a; The SetWindowsHookEx function installs an application-defined hook procedure into a hook chain. You would install a hook procedure to monitor the system for certain types of events. These events are associated either wit…

注入(4)--消息钩子注入(SetWindowsHookEX)

SetWindowsHookEx函数是微软提供给程序开发人员进行消息拦截的一个API。不过,他的功能不仅可以用作消息拦截,还可以进行DLL注入。 SetWindowsHookEx原型声明如下: WINUSERAPI HHOOK WINAPI SetWindowsHookExW(_In_ int idHook,_In_ HOOKPROC lpfn,_In_opt_ HINSTANCE hmod,…

DLL注入技术之消息钩子注入

消息钩子注入原理是利用Windows 系统中SetWindowsHookEx()这个API&#xff0c;他可以拦截目标进程的消息到指定的DLL中导出的函数&#xff0c;利用这个特性&#xff0c;我们可以将DLL注入到指定进程中。主要流程如下图所示 1&#xff0e;准备阶段 需要编写一个DLL&#xff…

关于采用消息钩子机制的透明加密的简单破解

采用消息钩子机制的透明加密方式在各大企业中很常见&#xff0c;简单实用。文件在磁盘上以密文方式存储&#xff0c;打开时首先被加密软件客户端注入的钩子&#xff08;hook&#xff09;截获&#xff0c;解密成明文后再提交给相应程序&#xff1b;保存时同样被钩子截获&#xf…

VC 消息钩子编程

分享一下我老师大神的人工智能教程&#xff01;零基础&#xff0c;通俗易懂&#xff01;http://blog.csdn.net/jiangjunshow 也欢迎大家转载本篇文章。分享知识&#xff0c;造福人民&#xff0c;实现我们中华民族伟大复兴&#xff01; 一、消息钩子的概念 1、基本概念 Windows应…

Windows消息钩子[键盘监控]

之前看书&#xff0c;看到一眼消息钩子&#xff0c;一直没实践&#xff0c;现在有空弄了下&#xff0c; 主要原理是利用windows自带SetWindowsHookEx API函数 HHOOK SetWindowsHookEx( int idHook, //hook形式 HOOKPROC lpfn //hook过程 HI…

一、C++反作弊对抗实战 (基础篇 —— 4.利用消息钩子注入DLL)

这里将主要用到Windows API函数SetWindowsHookEx,它是微软提供给程序开发人员进行消息拦截的一个API,不过它的功能不仅用作消息拦截,还可以进行DLL注入。 一、关于SetWindowsHookEx 提这个函数在微软官网MSDN文档中原型声明如下: SetWindowsHookExA function (winuser.h…

windows10 记事本进程 键盘消息钩子 dll注入

看了很多文档&#xff0c;垮了很多坎&#xff0c;终于完成了这个demo&#xff1b; 有很多个人理解&#xff0c;可能不完全正确&#xff0c;见谅&#xff1b; 先上实现的图片&#xff1a; 如图&#xff0c;我通过SetWindowsHookEx()函数向记事本进程中当前窗口线程注入了自己写…

消息钩子学习工程

前奏 近来一直在自学Windows Hook相关的知识&#xff0c;已经尝试多种注入方式。尤其对消息钩子方式很感兴趣&#xff0c;因为看到Spy能够截获系统中绝大多数应用的消息流&#xff0c;就很想知道它的工作原理&#xff0c;打算制作属于自己的Spy。 消息钩子简介&#xff1a; 消息…

DLL注入技术之消息钩子注入(HOOK简单的实现)

低头不是认输&#xff0c;是要看清自己的路。仰头不是骄傲&#xff0c;是看见自己的天空。——致自己 Hook&#xff0c;是Windows消息处理机制的一个平台&#xff0c;应用程序可以在上面设置子程序以监视指定窗口的某种消息&#xff0c;而且所监视的窗口可以是其他进程所创建的…

powerdesigner制作数据字典

powerdesigner制作数据字典TOC 配置好数据库连接之后&#xff0c;点击File→New Model 这步是默认的点OK就行。 数据传输完之后点击保存。 选择好保存路径后&#xff0c;关闭软件&#xff08;关闭时注意选择保存&#xff09;&#xff0c;然后再重现打开。 重新打开Po…

设计 - 数据字典

文档分类 写文档目的 你有没有遇到过开晨会、周会的时候某个问题已经讨论的很清晰。 但是几天后或者临近周末的时候再说这个问题的时候&#xff0c;团队中有的童鞋会说:“我不知道&#xff0c;没有说过这个问题或者这个方案”&#xff0c;因此而造成的BB事很伤神费心。 为了避免…