您的位置:首页 > 移动开发 > Android开发

《Android源码设计模式解析与实战》读书笔记(十二)

2015-12-28 09:00 435 查看

第十二章、观察者模式

观察者模式是一个使用率非常高的模式,它最常用在GUI系统、订阅–发布系统。因为这个模式的一个重要作用就是解耦,将被观察者和观察者解耦,使得它们之间的依赖性更小,甚至做到毫无依赖。比如安卓的开源项目EventBus、Otto、AndroidEventBus等事件总线类的和RxJava响应式编程其核心都是使用观察者模式。

1.定义

观察者模式是一种行为类模式,它定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并被自动更新。

2.使用场景

(1)关联行为场景,需要注意的是,关联行为是可拆分的,而不是“组合”关系。

(2)事件多级触发场景。

(3)跨系统的消息交换场景,如消息队列、事件总线的处理机制。

3.简单实现

这里举一个追剧的例子,平常为了不错过最新的电视剧我们会订阅或关注这个电视剧,当电视剧更新后会第一时间推送给我们,下来就简单实现一下。

抽象观察者类

[code]/**
 *  抽象观察者类,为所有具体观察者定义一个接口,在得到通知时更新自己
 */
public interface Observer {
    /**
     *  有更新
     *  
     *  @param message 消息
     */
    public void update(String message);

}


抽象被观察者类

[code]/**
 * 抽象被观察者类
 */
public interface Observable {

    /**
     * 推送消息
     * 
     * @param message 内容
     */
    void push(String message);

    /**
     * 订阅
     * 
     * @param observer 订阅者
     */
    void register(Observer observer);
}


具体的观察者类

[code]/**
 * 具体的观察者类,也就是订阅者
 */
public class User implements Observer {

    @Override
    public void update(String message) {
        System.out.println(name + "," + message + "更新了!");

    }

    // 订阅者的名字
    private String name;

    public User(String name) {
        this.name = name;
    }
}


具体的被观察者类

[code]/**
 *  具体的被观察者类,也就是订阅的节目
 */
public class Teleplay implements Observable{

    private List<Observer> list = new ArrayList<Observer>();//储存订阅者

    @Override
    public void push(String message) {
        for(Observer observer:list){
            observer.update(message);
        }
    }

    @Override
    public void register(Observer observer) {
        list.add(observer);
    }

}


实现

[code]public class Client {
    public static void main(String[] args) {
        //被观察者,这里就是用户订阅的电视剧
        Teleplay teleplay = new Teleplay();
        //观察者,这里就是订阅用户
        User user1 = new User("小明");
        User user2 = new User("小光");
        User user3 = new User("小兰");
        //订阅
        teleplay.register(user1);
        teleplay.register(user2);
        teleplay.register(user3);
        //推送新消息
        teleplay.push("xxx电视剧");
    }
}


结果

[code]小明,xxx电视剧更新了!
小光,xxx电视剧更新了!
小兰,xxx电视剧更新了!


由上面的代码可以看出实现了一对多的消息推送,推送消息都是依赖Observer和Observable这些抽象类,而User和Teleplay完全没有耦合,保证了订阅系统的灵活性和可扩展性。

4.Android源码中的观察者模式

1.BaseAdapter

BaseAdapter我相信大家都不陌生,在ListView的适配器中我们都是继承它。下面来简单分析分析。

BaseAdapter 部分代码:

[code]public abstract class BaseAdapter implements ListAdapter, SpinnerAdapter {

    //数据集观察者
    private final DataSetObservable mDataSetObservable = new DataSetObservable();

    public boolean hasStableIds() {
        return false;
    }

    public void registerDataSetObserver(DataSetObserver observer) {
        mDataSetObservable.registerObserver(observer);
    }

    public void unregisterDataSetObserver(DataSetObserver observer) {
        mDataSetObservable.unregisterObserver(observer);
    }

    /**
     * 当数据集变化时,通知所有观察者
     */
    public void notifyDataSetChanged() {
        mDataSetObservable.notifyChanged();
    }


看看mDataSetObservable.notifyChanged()方法:

[code]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) {
            // since onChanged() is implemented by the app, it could do anything, including
            // removing itself from {@link mObservers} - and that could cause problems if
            // an iterator is used on the ArrayList {@link mObservers}.
            // to avoid such problems, just march thru the list in the reverse order.
            for (int i = mObservers.size() - 1; i >= 0; i--) {
                mObservers.get(i).onChanged();
            }
        }
    }


可以看出在mDataSetObservable.notifyChanged()中遍历所有观察者,并调用他们的onChanged(),从而告知观察者发生了什么。

那么观察者怎么来的,那就是setAdapter方法,代码如下:

[code] @Override
    public void setAdapter(ListAdapter adapter) {
        if (mAdapter != null && mDataSetObserver != null) {
            mAdapter.unregisterDataSetObserver(mDataSetObserver);
        }

        resetList();
        mRecycler.clear();

        if (mHeaderViewInfos.size() > 0|| mFooterViewInfos.size() > 0) {
            mAdapter = new HeaderViewListAdapter(mHeaderViewInfos, mFooterViewInfos, adapter);
        } else {
            mAdapter = adapter;
        }

        mOldSelectedPosition = INVALID_POSITION;
        mOldSelectedRowId = INVALID_ROW_ID;

        // AbsListView#setAdapter will update choice mode states.
        super.setAdapter(adapter);

        if (mAdapter != null) {
            mAreAllItemsSelectable = mAdapter.areAllItemsEnabled();
            mOldItemCount = mItemCount;
            mItemCount = mAdapter.getCount();
            checkFocus();

            mDataSetObserver = new AdapterDataSetObserver();
            mAdapter.registerDataSetObserver(mDataSetObserver);//注册观察者

            ......省略
        }


AdapterDataSetObserver定义在ListView的父类AbsListView中,是一个数据集观察者,代码:

[code]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, 代码如下 :

[code]class AdapterDataSetObserver extends DataSetObserver {

        private Parcelable mInstanceState = null;
        // 上文有说道,调用Adapter的notifyDataSetChanged的时候会调用所有观察者的onChanged方法,核心实现就在这里
        @Override
        public void onChanged() {
            mDataChanged = true;
            mOldItemCount = mItemCount;
            // 获取Adapter中数据的数量
            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();
            // 重新布局ListView、GridView等AdapterView组件
            requestLayout();
        }

        // 代码省略

        public void clearSavedState() {
            mInstanceState = null;
        }
    }


当ListView的数据发生变化时,调用Adapter的notifyDataSetChanged函数,这个函数又会调用DataSetObservable的notifyChanged函数,这个函数会调用所有观察者 (AdapterDataSetObserver) 的onChanged方法。这就是一个观察者模式!

5.总结

1.优点

(1)观察者和被观察者之间是抽象耦合,应对业务变化。

(2)增强系统的灵活性和可扩展性。

2.缺点

在应用观察者模式时需要考虑一下开发效率和运行效率的问题,程序中包括一个被观察者、多个观察者,开发、调试等内容会比较复杂,而且在Java中消息的通知一般是顺序执行,那么一个观察者卡顿,会影响整体的执行效率,在这种情况下,一般会采用异步实现。

6.参考

链接:Android 设计模式 之 观察者模式
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: