android设计模式之观察者模式

观察者模式介绍

观察者模式是一个使用率非常高的模式,它最常用的地方就是GUI系统、订阅–发布系统。因为这个模式的一个重要作用就是解耦,将观察者和被观察者解耦,使得它们之间的依赖性更小,甚至做到毫无依赖。

观察者模式的定义:

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

使用情景:

第一、当一个抽象模型有两个方面,其中一个方面的操作依赖于另一个方面的状态变化。

第二、如果在更改一个对象的时候,需要同时连带改变其他的对象,而且不知道究竟应该有多少对象需要被连带改变。

第三、当一个对象必须通知其他的对象,但是你又希望这个对象和其他被他通知的对象是松散耦合的。

观察者模式的UML类图,如图

这里写图片描述

角色介绍:

(1)Subject(被观察者) 被观察的对象。当需要被观察的状态发生变化时,需要通知队列中所有观察者对象。Subject需要维持(添加,删除,通知)一个观察者对象的队列列表。 
(2)ConcreteSubject 被观察者的具体实现。包含一些基本的属性状态及其他操作。 
(3)Observer(观察者) 接口或抽象类。当Subject的状态发生变化时,Observer对象将通过一个callback函数得到通知。 
(4)ConcreteObserver 观察者的具体实现。得到通知后将完成一些具体的业务逻辑处理。

JDK提供了对observer设计模式的支持:

  • 通过java.util.Observable类扮演Subject角色,一个类只需通过继承java.util.Observable类便可担当ConcreteSubject角色;
  • 通过java.util.Observer接口扮演Observer角色,一个类只需实现java.util.Observer接口便可担当ConcreteObserver角色。
  • java.util.Observable的实现类通过调用setChanged()方法以及notifyObservers(Object)方法便可简单地通知Observer。


观察者模式的实现(两种方式,推模型和拉模型):

推模型:目标对象主动向观察者推送目标的详细信息,推送的信息通常是目标对象的全部或部分数据。

拉模型:目标对象在通知观察者时候,只传递少量信息。

如果观察者需要更具体的信息,由观察者主动到目标对象中获取,相当于观察者主动从目标拉数据;

一般这种模型的实现中,会把目标对象通过update方法传递给观察者。

二者比较:推模型是假定目标对象知道观察者需要的数据,使得观察者对象难以复用;拉模型是目标对象不知道观察者具体需要什么数据,因此把自身传递给观察者,由观察者来取,基本上适应各种情况的需要。

观察者模式的简单实现

玩LOL游戏的知道腾讯服务器会定时更新游戏版本,比如增加新英雄了等,在这个场景中,千千万万玩游戏的Player就是观察者,腾讯服务器LOLServer其实就是被观察者,当LOLSever有更新时会通知所有安装了LOL客户端的Player,代码实现如下:

先写一个玩家Player类,作为观察者:
import java.util.Observable;
import java.util.Observer;

public class Player implements Observer{//继承Observer接口

    public String name;//姓名
    public Player(String aName){
        name=aName;
    }
    //重写父类的update()方法
    @Override
    public void update(Observable o, Object arg) {
        // TODO Auto-generated method stub
        System.out.println("Hello,"+name+",LOL更新啦,内容:"+arg);
    }

    @Override
    public String toString() {
        return "玩家:"+name;
    }
}


然后LOLServer类,作为被观察者:
import java.util.Observable;

public class LOLServer extends Observable{
    public void postNewPublication(String content){
        //标识内容或者状态发生改变,不可少
        setChanged();
        //通知所有观察者
        notifyObservers(content);//推模型,没有参数的时候是拉模式
    }
}

具体被观察者将更新内容发布到每一个观察者Test类:
public class Test {
    public static void main(String[] args) {
        //1 创建被观察的角色
        LOLServer lolServer=new LOLServer();
        //2 创建观察者
        Player player1=new Player("李彦宏");
        Player player2=new Player("马云");
        Player player3=new Player("马化腾");
        //3 将观察者注册到可观察对象的观察者列表中
        lolServer.addObserver(player1);
        lolServer.addObserver(player2);
        lolServer.addObserver(player3);
        //4 发布消息
        lolServer.postNewPublication("死亡如风,常伴吾身!");
    }
}


打印结果如下:

Hello,马化腾,LOL更新啦,内容:死亡如风,常伴吾身!
Hello,马云,LOL更新啦,内容:死亡如风,常伴吾身!
Hello,李彦宏,LOL更新啦,内容:死亡如风,常伴吾身!

Android源码中的观察者模式

ListView是Android中最重要的控件之一,而ListView最重要的一个功能就是Adapter。通常,在我们往ListView中添加数据后,都会调用Adapter的notifyDataSetChanged,这个方法定义在BaseAdapter中,具体代码如下:

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();
    }
}


这里BaseAdapter 就是一个观察者模式,那么BaseAdapter 是如何运作的呢?谁是观察者?谁是被观察者呢?被观察者是如何发布新的内容的?首先,我们看看 mDataSetObservable.notifyChanged()函数中看看:

//数据集观察者
public class DataSetObservable extends Observable<DataSetObserver> {
    /**
     * Invokes {@link DataSetObserver#onChanged} on each observer.
     * Called when the contents of the data set have changed.  The recipient
     * will obtain the new contents the next time it queries the data set.
     */
    public void notifyChanged() {
        synchronized(mObservers) {
        //调用所有观察者的onChaged函数来通知他们被观察者发生了变化
            for (int i = mObservers.size() - 1; i >= 0; i--) {
                mObservers.get(i).onChanged();
            }
        }
    }


这个代码很简单,就是在for循环中遍历所有的观察者,并且调用他们的onChanged方法,从而告知观察者发生了变化。

那么这些观察者是从哪里来的呢?其实这些观察者就是ListView通过setAdapter方法设置Adapter产生的,相关代码如下:

    @Override
    public void setAdapter(ListAdapter adapter) {
    //如果已经有了一个Adapter,那么先注销该adapter对应的观察者
        if (mAdapter != null && mDataSetObserver != null) {
            mAdapter.unregisterDataSetObserver(mDataSetObserver);
        }
       //代码省略
        super.setAdapter(adapter);

        if (mAdapter != null) {
            mOldItemCount = mItemCount;
            mItemCount = mAdapter.getCount();//获取数据的总数
            mDataChanged = true;
            checkFocus();
          //创建一个数据集观察者
            mDataSetObserver = new AdapterDataSetObserver();
           mAdapter.registerDataSetObserver(mDataSetObserver);//将这个观察者注册到Adapter中,实际是注册到了DataSetObservable中
            //代码省略
            requestLayout();
    }


在代码中我们可以看到,在设置adapter的时候会构建一个AdapterDataSetObserver,这就是上面说到的观察者,最后将AdapterDataSetObserver这个观察者注册到Adapter中,这样我们的观察者和被观察者都已经有了,那么AdapterDataSetObserver实际上是个什么东西呢?它是怎么运作的?

我们再看看AdapterDataSetObserver,它定义在ListView的父类AbsListView中,具体代码如下:

 class AdapterDataSetObserver extends AdapterView<ListAdapter>.AdapterDataSetObserver {
        @Override
        public void onChanged() {
            super.onChanged();
            if (mFastScroller != null) {
                mFastScroller.onSectionsChanged();
            }
        }

        @Override
        public void onInvalidated() {
            super.onInvalidated();
            if (mFastScroller != null) {
                mFastScroller.onSectionsChanged();
            }
        }
    }


它又继承自AbsListView的父类AdapterView的AdapterDataSetObserver,具体代码如下:

 class AdapterDataSetObserver extends DataSetObserver {

        private Parcelable mInstanceState = null;
//上面讲过,调用adapter的notifyDataSetChanged时会调用所有观察者的onChanged方法,核心实现就在这里
        @Override
        public void onChanged() {
            mDataChanged = true;
            mOldItemCount = mItemCount;
            mItemCount = getAdapter().getCount();//获取adapter中数据的总量
            if (AdapterView.this.getAdapter().hasStableIds() && mInstanceState != null
                    && mOldItemCount == 0 && mItemCount > 0) {      AdapterView.this.onRestoreInstanceState(mInstanceState);
                mInstanceState = null;
            } else {
                rememberSyncState();
            }
            checkFocus();
            //重新布局Listview、GridView等AdapterView组件
            requestLayout();
        }
        public void clearSavedState() {
            mInstanceState = null;
        }
    }


到这里我们知道了,当ListView的数据发生变化的时候,调用Adapter的notifyDataSetChanged函数,这个函数又会调用DataSetObservable的notifyChanged函数,这个函数又会调用所有观察者(AdapterDataSetObserver)的onChanged方法,在onChanged函数中又会调用ListView重新布局的函数requestLayout使得ListView重新刷新界面,这就是一个观察者模式。

总结: 

观察者模式主要的作用就是对象解耦,将观察者与被观察者完全隔离,只依赖于Observer与Observable抽象

优点:

第一 观察者模式实现了观察者和目标之间的抽象耦合

第二 观察者模式实现了动态联动

第三 观察者模式支持广播通信

缺点:

可能引起无畏的操作(可以根据要通知的内容区别对待观察者)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值