Android 最常用的设计模式二 安卓Rxjava源码分析—观察者模式Observer(有实例)

Android 最常用的设计模式一 安卓源码MediaManager分析—单例模式singleInstance

https://blog.csdn.net/WHB20081815/article/details/77970206

Android 最常用的设计模式二 安卓Rxjava源码分析—观察者模式Observer(有实例)

https://blog.csdn.net/WHB20081815/article/details/77970133

Android 最常用的设计模式三 安卓源码okhttp分析—— 代理模式(proxy)

https://blog.csdn.net/WHB20081815/article/details/77982008

Android 最常用的设计模式十一安卓源码分析——组合模式(component)

https://blog.csdn.net/WHB20081815/article/details/77980367

 

1.什么是观察者模式

2.优点是什么?怎么解耦

3.4个要素是什么?

4.应用场景 demo分析

5.android的场景

 

 

情景1

有一种短信服务,比如天气预报服务,一旦你订阅该服务,你只需按月付费,付完费后,每天一旦有天气信息更新,它就会及时向你发送最新的天气信息。

 

 

       什么是观察者模式?一般提到原告,必然脑子立刻联想到被告,观察者和被观察者就如同原告和被告总是那么成对出现。观察者模式,又被叫做订阅模式,有订阅者和发布者。当下IPHONE6异常火爆,国内粉丝要想购买,那必须得预定,必须到它苹果官方去预定,填一大堆资料,交不交钱我不知道,反正得预定登记。等粉丝等到两眼欲穿、花儿快谢了时候,它粉墨登场了,官方以高姿态从容向预定过的粉丝发售。这苹果就是被观察者,粉丝就是观察者,观察者和被观察者之间需要建立联系,那就是登记。登记过后,被观察者拿捏火候觉得时机成熟的时候,就以权位者姿态向观察者抛出绣球,观察者迫不及待的伸出双手牢牢抓住后,满心欢喜的赞美苹果的伟大和自己的庆幸。睁大眼睛盯着目标看,期待期望结果,这就是观察者模式。

 

1.意图
定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新

主要解决一个对象状态改变给其他对象通知的问题,而且要考虑到易用和低耦合,保证高度的协作。

/**
 * 我们来使用一下,我们定义了一个天气变换的主题,也就是被观察者,还有两个观察者观察天气变换,一旦变换了,就打印出天气信息,
 * 注意一定要调用被观察者的register进行注册,否则会收不到变换信息。
 * 而一旦不敢兴趣了,直接调用unregister方法进行取消注册即可
 */
public void ObserverTest(){

    //天气预报
    Observable<Weather> observable=new Observable<Weather>();


    Observer<Weather> observer1=new Observer<Weather>() {
        @Override
        public void onUpdate(Observable<Weather> observable, Weather data) {
            System.out.println("观察者1"+data.toString());
        }
    };
    Observer<Weather> observer2=new Observer<Weather>() {
        @Override
        public void onUpdate(Observable<Weather> observable, Weather data) {
            System.out.println("观察者2"+data.toString());
        }
    };

    //注册观察者
    observable.register(observer1);
    observable.register(observer2);


    //天气发生了改变,通知观察者,注册了的观察者就能收到相应的信息
    Weather weather=new Weather("晴转多云");
    observable.notifyObservers(weather);

    Weather weather1=new Weather("多云转阴");
    observable.notifyObservers(weather1);

    observable.unregister(observer1);

    Weather weather2=new Weather("台风");
    observable.notifyObservers(weather2);
}

 

/**
 * Created by Administrator on 2017/9/13.
 * 封装业务,观察者和被观察者的业务封装
 * 观察者:注册监听,谁注册谁能收到
 * 被观察者:有信息变化的时候通知观察者
 * 
 */

public class Observable <T>{

    List<Observer<T>> mObservers = new ArrayList<Observer<T>>();

    //注册
    public void register(Observer<T> observer) {
        if (observer == null) {
            throw new NullPointerException("observer == null");
        }
        synchronized (this) {
            if (!mObservers.contains(observer))
                mObservers.add(observer);
        }
    }

    /**反注册*/
    public synchronized void unregister(Observer<T> observer) {
        mObservers.remove(observer);
    }

    public void notifyObservers(T data) {
        for (Observer<T> observer : mObservers) {
            observer.onUpdate(this, data);
        }
    }

}

 

 

/**
 * Created by Administrator on 2017/9/13.
 * 观察者得到的更新接口
 */

public interface Observer <T> {

    void onUpdate(Observable<T> observable,T data);

}

 

public class Weather {


    public Weather(String description){
        this.description=description;
    }

    private String description;

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }


}

 

这套系统中主要包括三个部分:气象站(获取天气数据的物理设备)、WeatherData(追踪来自气象站的数据,并更新公告牌)、公告牌(用于展示天气数据)

错误示范

我们现来看看隔壁老王的实现思路:

public class WeatherData {

    //实例变量声明
    ...

    public void measurementsChanged() {

        float temperature = getTemperature();
        float humidity = getHumidity();
        float pressure = getPressure();
        List<Float> forecastTemperatures = getForecastTemperatures();

        //更新公告牌
        currentConditionsDisplay.update(temperature, humidity, pressure);
        forecastDisplay.update(forecastTemperatures);
    }
    ...
}复制代码

上面这段代码是典型的针对实现编程,这会导致我们以后增加或删除公告牌时必须修改程序。我们现在来看看观察者模式,然后再回来看看如何将观察者模式应用到这个程序。

 

主题接口

/**
 * 主题(发布者、被观察者) 被观察者一般保函3个:注册,移除和通知(和点击事件一样)
 */
public interface Subject {

    /**
     * 注册观察者
     */
    void registerObserver(Observer observer);

    /**
     * 移除观察者
     */
    void removeObserver(Observer observer);

    /**
     * 通知观察者
     */
    void notifyObservers(); 
}

观察者接口


/**
 * 观察者(用于更新的一个接口方法)
 */
public interface Observer {
    void update();
}复制代码

公告牌用于显示的公共接口

public interface DisplayElement {
    void display();
}
中间类:

下面我们再来看看WeatherData是如何实现的:被观察者的生命周期

public class WeatherData implements Subject {

    private List<Observer> observers;

    private float temperature;//温度
    private float humidity;//湿度
    private float pressure;//气压
    private List<Float> forecastTemperatures;//未来几天的温度

    public WeatherData() {
        this.observers = new ArrayList<Observer>();
    }

    @Override
    public void registerObserver(Observer observer) {
        this.observers.add(observer);
    }

    @Override
    public void removeObserver(Observer observer) {
        this.observers.remove(observer);
    }

    @Override
    public void notifyObservers() {
        for (Observer observer : observers) {
            observer.update();
        }
    }

    public void measurementsChanged() {
        notifyObservers();
    }

    public void setMeasurements(float temperature, float humidity, 
    float pressure, List<Float> forecastTemperatures) {
        this.temperature = temperature;
        this.humidity = humidity;
        this.pressure = pressure;
        this.forecastTemperatures = forecastTemperatures;
        measurementsChanged();
    }

    public float getTemperature() {
        return temperature;
    }

    public float getHumidity() {
        return humidity;
    }

    public float getPressure() {
        return pressure;
    }

    public List<Float> getForecastTemperatures() {
        return forecastTemperatures;
    }
}

显示当前天气的公告牌CurrentConditionsDisplay:观察者的更新方法和ui的显示方法

 

public class CurrentConditionsDisplay implements Observer, DisplayElement {

    private WeatherData weatherData;

    private float temperature;//温度
    private float humidity;//湿度
    private float pressure;//气压

    public CurrentConditionsDisplay(WeatherData weatherData) {
        this.weatherData = weatherData;
        this.weatherData.registerObserver(this);
    }

    @Override
    public void display() {
        System.out.println("当前温度为:" + this.temperature + "℃");
        System.out.println("当前湿度为:" + this.humidity);
        System.out.println("当前气压为:" + this.pressure);
    }

    @Override
    public void update() {
        this.temperature = this.weatherData.getTemperature();
        this.humidity = this.weatherData.getHumidity();
        this.pressure = this.weatherData.getPressure();
        display();
    }
}
好处:后面如果我们需要增加或者删除公告牌就只需要新增或者删除实现了ObserverDisplayElement接口的公告牌就好了。

 

总结:

观察者模式的结构中包含四种角色:

(1)主题(Subject):主题是一个接口,该接口规定了具体主题需要实现的方法,比如,添加、删除观察者以及通知观察者更新数据的方法。

(2)观察者(Observer):观察者是一个接口,该接口规定了具体观察者用来更新数据的方法。

(3)具体主题(ConcreteSubject):具体主题是实现主题接口类的一个实例,该实例包含有可以经常发生变化的数据。具体主题需使用一个集合,比如ArrayList,存放观察者的引用,以便数据变化时通知具体观察者。

(4)具体观察者(ConcreteObserver):具体观察者是实现观察者接口类的一个实例。具体观察者包含有可以存放具体主题引用的主题接口变量,以便具体观察者让具体主题将自己的引用添加到具体主题的集合中,使自己成为它的观察者,或让这个具体主题将自己从具体主题的集合中删除,使自己不再是它的观察者。

来源: https://www.cnblogs.com/xuwendong/p/9814417.html

 

1.观察者(封装更新方法)

2.被观察者———转接桥梁(封装了注册和更新的方法)

3.事件(实体信息,内容)

4.观察者模式的三个典型方法它都具有,即注册,取消注册,发送事件

5.传输数据,有注册信息相关的组件就用到了观察者模式

 

实现观察者模式有很多形式,一种是“注册---通知---撤销注册”的形式。

 

观察者模式的应用场景

  • 当一个对象的改变需要通知其它对象改变时,而且它不知道具体有多少个对象有待改变时。
  • 当一个对象必须通知其它对象,而它又不能假定其它对象是谁
  • 跨系统的消息交换场景,如消息队列、事件总线的处理机制。
  • 1、 对一个对象状态的更新,需要其他对象同步更新,而且其他对象的数量动态可变。

    2、 对象仅需要将自己的更新通知给其他对象而不需要知道其他对象的细节。

安卓中用到的观察者模式

1.观察者模式:

电视前的你也就是观察者可以看,(对象发生变化)电视里被观察者做了别的动作,那么电视前的所有人看到的也就变了,在同一时间改变所有观众看到的画面。

比如说BaseAdapter AbsListView  

RecyclerView 

 

我们可以通过BaseAdapter.registerDataSetObserver和BaseAdapter.unregisterDataSetObserver两方法来向BaseAdater注册、注销一个DataSetObserver。这个过程中,DataSetObserver就是一个观察者,它一旦发现BaseAdapter内部数据有变量,就会通过回调方法DataSetObserver.onChanged和DataSetObserver.onInvalidated来通知DataSetObserver的实现类。事件通知也是观察者模式

简介:一个对象发生改变时,所有信赖于它的对象自动做相应改变。

<span style="color:gray"><span style="color:#abb2bf"><code><span style="color:#c678dd">public</span> <span style="color:#c678dd">abstract</span> <span style="color:#c678dd">class</span> <span style="color:#e6c07b">BaseAdapter</span> <span style="color:#c678dd">implements</span> <span style="color:#e6c07b">ListAdapter</span>, <span style="color:#e6c07b">SpinnerAdapter</span> {
     <span style="color:#929292">//数据集被观察者</span>
    <span style="color:#c678dd">private</span> <span style="color:#c678dd">final</span> DataSetObservable mDataSetObservable = <span style="color:#c678dd">new</span> DataSetObservable();

    <span style="color:#929292">//注册观察者</span>
    <span style="color:#c678dd">public</span> <span style="color:#c678dd">void</span> <span style="color:#61aeee">registerDataSetObserver</span>(DataSetObserver observer) {
        mDataSetObservable.registerObserver(observer);
    }
    <span style="color:#929292">//注销观察者</span>
    <span style="color:#c678dd">public</span> <span style="color:#c678dd">void</span> <span style="color:#61aeee">unregisterDataSetObserver</span>(DataSetObserver observer) {
        mDataSetObservable.unregisterObserver(observer);
    }
    <span style="color:#929292">//数据集改变时,通知所有观察者</span>
    <span style="color:#c678dd">public</span> <span style="color:#c678dd">void</span> <span style="color:#61aeee">notifyDataSetChanged</span>() {
        mDataSetObservable.notifyChanged();
    }
}
    <span style="color:#929292">//其他代码略</span></code>
</span></span>

来源: https://www.jianshu.com/p/8f32da74cd8b

2.Android的广播机制LocalBroadcastManager

 

我们平时使用本地广播主要就是下面四个方法

 

LocalBroadcastManager localBroadcastManager=LocalBroadcastManager.getInstance(this);
localBroadcastManager.registerReceiver(BroadcastReceiver receiver, IntentFilter filter);
localBroadcastManager.unregisterReceiver(BroadcastReceiver receiver);
localBroadcastManager.sendBroadcast(Intent intent)

 

3.EventBus

 

观察者模式的三个典型方法它都具有,即注册,取消注册,发送事件

 

EventBus.getDefault().register(Object subscriber);
EventBus.getDefault().unregister(Object subscriber);
EventBus.getDefault().post(Object event);

 

http://www.cnblogs.com/shijiacheng/p/5059067.html

 

4.RecyclerView中的addOnScrollListener方法

 

 

 

观察者模式的优点:

1、 Subject和Observer之间是松偶合的,分别可以各自独立改变。

2、 Subject在发送广播通知的时候,无须指定具体的Observer,Observer可以自己决定是否要订阅Subject的通知。

3、 遵守大部分GRASP原则和常用设计原则,高内聚、低偶合。

5.。RxJava

 

自己在项目中的运用如下:

GPS位置信息监听

  上面对按钮监听是属于一对一的观察者模式,当然你也可以用一个Listener监听多个按钮。下面我们再讲一个标准的一对多的观察者模式的应用。在我们使用GPS模块的时候,需要监听GPS模块位置变化,通常我们会编写下面代码:

 

//Edited by mythou
//http://www.cnblogs.com/mythou/
// 通过GPS定位
String LocateType= locationManager.GPS_PROVIDER;
Location location = locationManager.getLastKnownLocation(LocateType);
// 设置监听器,设置自动更新间隔这里设置1000ms,移动距离:0米。
locationManager.requestLocationUpdates(provider, 1000, 0, locationListener);
// 设置状态监听回调函数。statusListener是监听的回调函数。locationManager.addGpsStatusListener(statusListener); 

//监听器实现private final GpsStatus.Listener statusListener = new GpsStatus.Listener() 
{
    public void onGpsStatusChanged(int event) 
  {
      // GPS状态变化时的回调,获取当前状态
      GpsStatus status = locationManager.getGpsStatus(null);
    //自己编写的方法,获取卫星状态相关数据
       GetGPSStatus(event, status);
    }
};

 

  GPS位置服务是Framework的一个系统层服务,整个系统只有一个运行的实例。但实际使用时,可能会出现好几个应用都在使用这个服务,因此会形成了一个一对多的观察者例子。这里不对代码进行深入对比讲解,只要对照上面的讲解,你就可以把目标对象、观察者接口、观察者实现、数据更新回调接口找出来。有兴趣的朋友还可以追查Android的源码,看看GpsStatus里面的具体实现。

 

观察者模式在实际项目的应用中非常常见,比如你到 ATM 机器上取钱,多次输错密码,卡就会被 ATM吞掉,吞卡动作发生的时候,会触发哪些事件呢?第一摄像头连续快拍,第二,通知监控系统,吞卡发生;第三,初始化 ATM 机屏幕,返回最初状态,你不能因为就吞了一张卡,整个 ATM 都不能用了吧,一般前两个动作都是通过观察者模式来完成的。观察者可以实现消息的广播,一个消息可以触发多个事件,这是观察者模式非常重要的功能。

 

继续以送快递为例,快递员有时只是把快递拉到楼下,然后就通知收件人下楼去取快递。

 

优点:(解耦,方便以后添加方法扩展)

  1、具体主题和具体观察者是松耦合关系。由于主题接口仅仅依赖于观察者接口,因此具体主题只是知道它的观察者是实现观察者接口的某个类的实例,但不需要知道具体是哪个类。同样,由于观察者仅仅依赖于主题接口,因此具体观察者只是知道它依赖的主题是实现主题接口的某个类的实例,但不需要知道具体是哪个类。

关于观察者的一切,主题只知道观察者实现了Observer接口,并不需要观察者具体的类是谁,做了什么或者其他细节

 

 

  • 解除观察者与主题之间的耦合。让耦合的双方都依赖于抽象,而不是依赖具体。从而使得各自的变化都不会影响另一边的变化。
  • 易于扩展,对同一主题新增观察者时无需修改原有代码。

 

 

  2、观察者模式满足“开-闭原则”。主题接口仅仅依赖于观察者接口,这样,就可以让创建具体主题的类也仅仅是依赖于观察者接口,因此,如果增加新的实现观察者接口的类,不必修改创建具体主题的类的代码。。同样,创建具体观察者的类仅仅依赖于主题接口,如果增加新的实现主题接口的类,也不必修改创建具体观察者类的代码。

缺点: 

  1、如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。(遍历太多了,可能会引起多余的数据通知。)

  2、如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃。(死循环)

  3、观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。


 

 

参考博客:

 

https://juejin.im/post/57de12355bbb50005e648bd8

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值