关闭

Android设计模式之观察者模式(Observer Pattern)

标签: android设计模式观察者模式adapter
1500人阅读 评论(1) 收藏 举报
分类:

观察者模式介绍

观察者模式是一个使用率非常高的模式,它最常用的地方就是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。

观察者模式的简单实现

玩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抽象。

3
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:154919次
    • 积分:2539
    • 等级:
    • 排名:第15875名
    • 原创:102篇
    • 转载:9篇
    • 译文:1篇
    • 评论:20条
    博客专栏
    最新评论