博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Android设计模式-观察者模式
阅读量:6406 次
发布时间:2019-06-23

本文共 6316 字,大约阅读时间需要 21 分钟。

原文地址 http://blog.csdn.net/qq_25806863/article/details/69218968

观察者模式是一种使用频率非常高的设计模式,最常用的地方就是订阅-发布系统。

这个模式的重要作用就是将观察者和被观察者解耦,使他们之间的依赖更小甚至没有。

定义

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

使用场景

关联行为场景,这个关联是可拆分的。将观察者和被观察者封装在不同的对象中,可以各自独立的变化。
当一个对象改变时,有其他对象要进行相应的变化,但是他并不知道有多少个对象需要变化。
跨系统的消息交换长江,如消息队列,时事件总线等
UML

Subject : 抽象被观察者(Observeable),吧所有观察者对象的医用保存在一个集合里,每个主题都可以有任意数量的观察者,抽象被观察者提供一个接口,可以增加和删除观察者对象。
ConcreteSubject: 具体的被观察者,将有关状态存入具体的观察者对象,在具体的被观察者内部状态发生变化时,给所有注册的观察者发送通知。
Observer : 抽象观察者,定义了一个更新接口,使得在得到被观察者的通知时更新自己。
ConcreteObserver : 具体的观察者,实现了抽象观察者锁定义的接口,用来在收到通知时更新自己。
简单实现
订阅模式就是个观察者模式,订阅后,被订阅的有更新就会提示你。

拿微信公众号举个例子吧.Java提供的有Observer和Observable类,可以很方便的实现观察者模式。

先定义一个订阅者,实现更新方法。

---------------------
作者:喵了个呜s
来源:CSDN
原文:https://blog.csdn.net/qq_25806863/article/details/69218968
版权声明:本文为博主原创文章,转载请附上博文链接!

public class User implements Observer {    public String name;    public User(String name) {        this.name = name;    }    @Override    public void update(Observable o, Object arg) {        System.out.println("Hi "+name +",公众号更新了内容:"+arg);    }}

定义一个可观察者,有变化时发布更新通知。

public class Gamedaily extends Observable {    public void postNewArticle(String content){        //内容发生改变        setChanged();        //通知所有订阅者改变的内容        notifyObservers(content);    }}

使用

public class Client {    public static void main(String[] args) {        Gamedaily gamedaily = new Gamedaily();        User user1 = new User("user1");        User user2 = new User("user2");        User user3 = new User("user3");        //将观察者注册到可观察者的通知列表中。        gamedaily.addObserver(user1);        gamedaily.addObserver(user2);        gamedaily.addObserver(user3);        gamedaily.postNewArticle("新文章来了");    }}

输出

当公众号发布新文章的时候,所有订阅者都收到的通知,并作出相应的改变。一个公众号对应多个订阅者,并且完全没有耦合。

Android源码中的观察者模式

通常在ListView的内容变化时,我们会调用notifyDataSetChanged()这个方法,然后ListView里面的数据就会进行更新。这个感觉就像是观察者模式。ListView在观察者内容,内容变化发布通知之后ListView就会更新数据。

看一下这个方法。

package android.widget;public abstract class BaseAdapter implements ListAdapter, SpinnerAdapter {    private final DataSetObservable mDataSetObservable = new DataSetObservable();    public void registerDataSetObserver(DataSetObserver observer) {        mDataSetObservable.registerObserver(observer);    }    public void unregisterDataSetObserver(DataSetObserver observer) {        mDataSetObservable.unregisterObserver(observer);    }    ......    public void notifyDataSetChanged() {        mDataSetObservable.notifyChanged();    }    ......}

这段代码可以看到这应该是一个观察者模式,而且这个一个被观察者,里面提供了注册和注销观察者以及通知观察者的方法。

这些方法是通过DataSetObservable这个类调用的:

package android.database;public class DataSetObservable extends Observable
{ public void notifyChanged() { synchronized(mObservers) { for (int i = mObservers.size() - 1; i >= 0; i--) { mObservers.get(i).onChanged(); } } } ......}
这个类继承自Observable,Observable中有一个protected final ArrayList
mObservers = new ArrayList
();, 用来保存注册的观察者。mDataSetObservable.registerObserver(observer)和mDataSetObservable.unregisterObserver(observer)分别就是增加和删除。在notifyChanged方法中,循环这个集合,调用每一个观察者的onChanged()方法。那么这些观察者是什么时候注册的呢?也就是ListView和Adapter什么时候成了订阅关系。在ListView的setAdapter()中
public class ListView extends AbsListView {    public void setAdapter(ListAdapter adapter) {        //如果已经有了一个adapter,注销这个adapter之前的观察者,        if (mAdapter != null && mDataSetObserver != null) {            mAdapter.unregisterDataSetObserver(mDataSetObserver);        }       ......       if (mHeaderViewInfos.size() > 0|| mFooterViewInfos.size() > 0) {            mAdapter = wrapHeaderListAdapterInternal(mHeaderViewInfos, mFooterViewInfos, adapter);        } else {            //将新的adapter赋给mAdapter            mAdapter = adapter;        }        ......        super.setAdapter(adapter);        if (mAdapter != null) {            mAreAllItemsSelectable = mAdapter.areAllItemsEnabled();            //保存之前的数据个数            mOldItemCount = mItemCount;            //获取新的个数            mItemCount = mAdapter.getCount();            checkFocus();            //创建数据集观察者            mDataSetObserver = new AdapterDataSetObserver();            //注册观察者            mAdapter.registerDataSetObserver(mDataSetObserver);            ...            }        } else {            ...        }        requestLayout();    }}

AdapterDataSetObserver是ListView的父类AbsListView的内部类

package android.widget;public abstract class AbsListView extends AdapterView
implements TextWatcher, ViewTreeObserver.OnGlobalLayoutListener, Filter.FilterListener, ViewTreeObserver.OnTouchModeChangeListener, RemoteViewsAdapter.RemoteAdapterConnectionCallback { class AdapterDataSetObserver extends AdapterView
.AdapterDataSetObserver { @Override public void onChanged() { super.onChanged(); if (mFastScroll != null) { mFastScroll.onSectionsChanged(); } } ······ }}

AdapterDataSetObserver是AdapterView.AdapterDataSetObserver的子类,所以要看super.onChanged()

package android.widget;public abstract class AdapterView
extends ViewGroup { class AdapterDataSetObserver extends DataSetObserver { private Parcelable mInstanceState = null; @Override public void onChanged() { mDataChanged = true; mOldItemCount = mItemCount; 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(); //重新布局 requestLayout(); } ...... }}

整理一下:当ListView数据变化时,调用Adapter的notifyDataSetChange方法,这个方法调用DataSetObservable的notifyChanged方法,这个方法又会调用所有观察者的onChanged方法,onChanged再调用重新布局View的方法,完成刷新数据的功能。

总结

优点
解除了观察者和被观察者的耦合,而且依赖的都是抽象,容易应对业务变化,各自的变化都不会影响另一个。
增强系统灵活性、可拓展性。
缺点
Java中的消息默认是顺序执行,如果一个观察者卡顿,会造成整个系统效率变低,可以考虑异步。
可能会引起无用的操作甚至错误的操作。

转载于:https://www.cnblogs.com/Im-Victor/p/6305976.html

你可能感兴趣的文章
delmatch oracle_完美完全卸载(清除)oracle数据库的方式(方法)
查看>>
pyqt 滚动条 美化_Pyqt5 关于流式布局和滚动条的综合使用示例代码
查看>>
51单机片 编译hex_单片机爬坑记-05-编译环境(完)
查看>>
java 正则表达式 img_Java正则表达式获得html字符串里的<img src=""/> 中的url列表
查看>>
dbutils java_Java篇-DBUtils与连接池
查看>>
java 文件crc校验_一个获取文件crc32校验码的简洁的java类 | 学步园
查看>>
java flatmapfunction_Java8 Stream flatmap中间操作用法解析
查看>>
java rmi spring 4.0_Java Spring RMI一些尝试
查看>>
JAVA怎么连接华为的HDFS系统_JAVA-API操作HDFS文件系统(HDFS核心类FileSystem的使用)...
查看>>
java牛客网四则运算_数据库刷题—牛客网(51-61)
查看>>
Java get set6_JDK6的新特性(转)
查看>>
java发送邮件 不登陆_Java邮件到Exchange Server“不支持登录方法”
查看>>
编程学习初体验(5. 如何自学编程)(2)
查看>>
思科ISR G1与ISR G1C的区别
查看>>
利用perl提取web配置文件中的域名对应的路径
查看>>
Centos5上安装JRE和LUMAQQ
查看>>
关于监控工具的主动发起性能测试
查看>>
我的友情链接
查看>>
OpenSSL学习(十六):基础-指令rand
查看>>
Apache+tomcat实现高可用WEB集群
查看>>