澳门1495

解析设计模式-观察者模式。设计模式之三:观察者模式。

十月 17th, 2018  |  球类运动

定义

观察者模式(Observer
Pattern):定义对象期间的平等种同等针对多靠关系,使得以一个靶状态产生转移时,其系依赖对象清一色落关照并吃自动更新

实际世界之模式

依照一些用户订阅了周刊,每次周刊发表之时光还见面送至用户眼前

照高考的下,发送广播通知考试完毕,考生都要停笔,教师要收卷

以打仗之时刻,指挥官发命令,战场上之大兵跟军命令决定进攻、撤退、驻守

起及时几栽档次

  • 通告-订阅模式
  • 型-视图模式
  • 源-监听模式
  • 从今属者模式

观察者模式
目介绍
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 参考文档:源码设计模式解析

简设计

目标

吃考察的目标,内置抽象观察者集合,定义增加、删除、通知抽象观察者的点子。目标类可以是空洞的吧堪是具体的。如果产生现实的架空业务要兑现,还得分出目标子类

虚幻观察者

扬言了更新数据的道,由目标调用

实际观察者

实现了纸上谈兵观察者的换代数据的措施

比方欲目标的一些态或者数额状态,可能还保持着对目标的援

图片 1

观察者模式-类图.png

好行使在平对大多的通信及。同时,目标与观察者没有最好强的乘以及干,增加还是减小观察者,不会见针对目标导致影响

0.自写的汇总案例

运实例

  • 案例
  • 证和截图
  • 模块:新闻,音乐,视频,图片,唐诗宋词,快递,天气,记事本,阅读器等等
  • 接口:七牛,阿里云,天行,干货集中营,极速数据,追书神器等等

HTTP DNS 解析性能监控

发如此一个场面,我们的采用接入了 HTTP DNS,接管了某些接口请求的 DNS
解析。现在某些有统计报告接口,在少数地方,需要 DNS
解析的部分信息,比如解析到的 IP,解析耗时,解析采用的域名服务器地址

我们可以运用观察者来化解者问题

起一个监控器,内置观察者队列,并提供方式来丰富、删除观察者

当 DNS
每次发起一不成解析,把多少统计后,交给监控器。然后监控通知所有观察者拿多少

概念目标类 DnsMonitor

public class DnsMonitor {

    private final List<MonitorWatcher> mWatcherList;

    public DnsMonitor() {
        mWatcherList = new CopyOnWriteArrayList<>();
    }

    @Override
    public void onParseResult(ResolveData data) {
        if (data == null || TextUtils.isEmpty(data.host)) {
            return;
        }

        // 通知观察者们,有解析数据了
        for (MonitorWatcher watcher : mWatcherList) {
            watcher.notifyResolveData(data);
        }
    }

    /**
     * 注册监视者
     */
    public void registerWatcher(MonitorWatcher watcher) {
        mWatcherList.add(watcher);
    }

    /**
     * 注销监视者
     */
    public void unregisterWatcher(MonitorWatcher watcher) {
        mWatcherList.remove(watcher);
    }
}

概念观察者

public interface MonitorWatcher {
    /**
     * 通知获取到的解析数据
     */
    void notifyResolveData(ResolveData data);
}

然后,我们的具备 DNS 解析器,在分析及结果后,调用的 onParseResult
把多少产生去

可以拿 Monitor
做成单例,或者放到单例内,这样尽管足以通经过都得看。所有的观察者们,只需要实现
MonitorWatcher,然后等着多少通知过来

实则这职能还有很多细节,比如安防唤醒观察者不死,还有什么给具备解析器使用和一个监视器。因为同这个模式无关,就无排出来了

1.观察者模式介绍

ContentObserver

发生这般一个求,我们怀念使明数据库有数的变动,有雷同栽结果方法,那就是是开个工作线程,去轮询访问。这样的做法会促成资源大量消耗

Android 提供的同一种植方法,称为内容观察者,可以监听数据库变化后会打招呼下

遵我们若监听屏幕亮度的别,并且做有事务。屏幕亮度变化之多少在系数据库里,我们得经
ContentObserver 很自在地取出

屏幕亮度对应的 Uri 可以这样获得

Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS)

开创观察者

    private static class ScreenBrightnessObserver extends ContentObserver {

        ScreenBrightnessObserver(@NonNull Handler handler) {
            super(handler);
        }

        @Override
        public void onChange(boolean selfChange) {
            super.onChange(selfChange);

            // 亮度发生变化了,可以查询最新的亮度,然后做相应的业务

        }
    }

接下来于页面启动的使用登记

mScreenBrightnessObserver = new ScreenBrightnessObserver(new Handler());
getContentResolver().registerContentObserver(Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS), true, mScreenBrightnessObserver);

当页面销毁之上注销

getContentResolver().unregisterContentObserver(mScreenBrightnessObserver);
  • 1.1 最常用之地方是GUI系统、订阅——发布网等
  • 1.2 重要作用就是解耦,使得其之间的负更有些,甚至就决不依赖
  • 1.3
    观察者模式还要给号称发布/订阅模式,观察者模式定义了同一种植同等针对性多的依靠关系,让多只观察者对象又监听某一个主题对象。这个主题对象在状态发生变化时,会通报所有观察者对象,使它会自动更新自己。
  • 1.4 举只例:
    纵然以csdn这个仿佛于博客的网站来说吧,如果你订阅了要说关注了一个领域,就能够接到这领域文章的推送,如果无眷顾,则未能够。是相当给产生一个总控制台(被观察者,持有数据源,这里的数据源是咱们每个订阅了底人数)通知下的观察者。

EventBus

EventBus 也是观察者模式的一律栽实现

要我们有差不多只目标,多独观察者,如果每个目标还失去管理观察者列表的话,维护起来老可怕

于是这里以抽象出一个层次,可以领略啊信中心,或者信息总线,内部维护在观察者的列表,目标发出多少变化交给这消息中心开展信息之分发及调度

图片 2

观察者模式-EventBus.png

EventBus
提供了一个异常有力消息总线,目标发生变化的时,把要通的音封装成一个个信息。把信通知被订阅该消息的观察者们

可以用 EventBus
在召开模块间的通信。把要通的数目变动封装成事件抛出来。通信的模块没有耦合,发送者不需要理解有哪接收者。EventBus
会通知到位

2.观察者使用状况

  • 事件多级触发场景
  • 逾系统的音交换场景,如信息队列,事件总线的拍卖体制

3.观察者UML图解

  • 3.1 关于UML类图
![](https://upload-images.jianshu.io/upload_images/4432347-27bf2c97c86c7c77.png)

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源码解析文章

任何证明

  • 知乎:https://www.zhihu.com/people/yang-chong-69-24/pins/posts
  • 领英:https://www.linkedin.com/in/chong-yang-049216146/
  • 简书:http://www.jianshu.com/u/b7b2c6ed9284
  • csdn:http://my.csdn.net/m0\_37700275
  • 网易博客:http://yangchong211.blog.163.com/
  • 新浪博客:http://blog.sina.com.cn/786041010yc
  • github:https://github.com/yangchong211
  • 喜马拉雅听书:http://www.ximalaya.com/zhubo/71989305/
  • 脉脉:yc930211
  • 360图书馆:http://www.360doc.com/myfiles.aspx
  • 开源中国:https://my.oschina.net/zbj1618/blog
  • 泡在网上的光阴:http://www.jcodecraeer.com/member/content\_list.php?channelid=1
  • 邮箱:yangchong211@163.com
  • 阿里云博客:https://yq.aliyun.com/users/article?spm=5176.100239.headeruserinfo.3.dT4bcV

相关文章

标签:, , , ,

Your Comments

近期评论

    功能


    网站地图xml地图