《设计模式》- 观察者模式

定义

定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则因此依赖于它的对象都会获得通知并被自动更新java

使用场景

  • 关联行为场景,须要注意的是,关联行为是可拆分的,而不是“组合”关系。
  • 时间多级触发场景
  • 跨系统的消息交换场景,如消息队列、时间总线的处理机制。

UML 类图

classDiagram
Subject o.. Observer
Subject <|-- ConcreteSubject
Observer <|-- ConcreteObserver
class Subject{
    <<abstract>>
    +register(Observer)
    +unregister(Observer)
    +nofityObservers(Object)
}
class ConcreteSubject{
    +nofityObservers(Object)
}
class Observer{
    <<interface>>
    +update(Object)
}
class ConcreteObserver{
    +update(Object)
}
  • Subject: 抽象主题,也就是被观察者(Observable)角色,抽象主题把因此观察者对象的引用保存在一个集合里,每一个主题均可以有任意数量的观察者,抽象主题提供一个接口,能够新增和删除观察者对象。
  • ConcerteSubject: 具体主题,该角色将有关状态存入具体观察者对象,在具体主题的内容状态发生改变时,给全部注册过的观察者发出通知,具体主题角色又叫作具体观察者(ConsreteObservable)角色。
  • Observer: 抽象观察者,改角色是观察者的抽象类,它定义了一个更新接口,使得在获得主题的更改通知时更新本身。
  • ConcreteObserver: 具体观察者,该角色实现抽象观察者所定义的更新接口,以便在主题状态发生改变时更新自身的状态。

Android 中的观察者模式

Android源码中有不少使用了观察者模式,好比OnClickListener、ContentObserver、 android.database.Observer 等。还有不少组件库Rxjava、RxAndroid、EventBus;这里咱们来看下经常使用的Adapter的notifyDataSetChanged()。android

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 里有一个DataSetObservable 的被观察者,经过register*()、unregister*()方法添加和删除观察者。咱们往下看DataSetObservable 这个类markdown

public class DataSetObservable extends Observable<DataSetObserver> {
    /** * 当数据变化时调用每一个观察者的onChanged() 方法通知它们 */
    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();
            }
        }
    }
}

复制代码

这里其实很简单,就是遍历全部观察者并调用它们的onChanged()。接下来咱们看是谁调用了BaseAdapter 的 registerDataSetObserver(DataSetObserver observer)方法。app

public void setAdapter(ListAdapter adapter) {
        if (mAdapter != null && mDataSetObserver != null) {
            mAdapter.unregisterDataSetObserver(mDataSetObserver);
        }
        
        //省略代码...

        // 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();
            //将这个观察者注册到 Adapter 的 DataSetObservable 中
            mAdapter.registerDataSetObserver(mDataSetObserver);
            //省略代码...
        } else {
            //省略代码...
        }

        requestLayout();
    }
复制代码

以上能够看出ListVeiw 中有一个观察者(AdapterDataSetObserver)在setAdapter() 的时候注册到了Adapter 的DataSetObservable 中,当Adapter 调用 notifyDataSetChanged() 方法时就会通知 ListView 中的观察者(AdapterDataSetObserver)更新状态。异步

小结

观察者模式主要的做用就是解耦,将观察者与被观察者彻底隔离,只依赖于 Observer 和 Observable 抽象,提供代码的灵活性和可扩展性。spa

优势: 观察者和被观察者直接是抽象耦合,应对业务变化。加强系统灵活性、可扩展性。code

缺点: 在应用观察者模式时须要考虑一下开发效率和运行效率问题,由于一个被观察者可能直接或间接有不少观察者,Java 消息中的通知默认顺序执行,通知到因此观察者可能须要花费些时间,若是一个观察者卡顿,会影响总体的执行效率,这里通常考虑采用异步的方式。orm

相关文章
相关标签/搜索