设计模式:观察者模式 源码分析和在 RecyclerView 中的体现

*本篇文章已授权微信公众号 guolin_blog (郭霖)独家发布

写在前面

最近在学习 EventBus 和 RxJava 相关知识,了解到两者都使用了观察者模式。以前对该模式只有一个模糊的概念,导致看 E 和 R 时一知半解,所以下定决心把这个模式仔细回顾和记录一下。

一、观察者模式相关概念

定义:一个对象和多个形成依赖关系,当一个对象改变状态,所以依赖于它的对象都会得到通知并执行相应逻辑。

简单理解:A 是被观察者,B、C、D 是观察者。当 A 发生变化时发出通知告知 B、C、D,然后 B、C、D 可根据 A 发送的数据来做具体的事情。

重要作用:解耦。也就是将观察者和被观察者解耦。

解耦的好处不用多说,设计模式中 单一职责原则 也表明我们希望每个实体(类、函数、模块等)能引起其改变的原因只有它自己。
也就是说,我们希望观察者的逻辑和被观察者的逻辑是分离的。

使用场景:
1.某些时候需要一些对象有所关联,而且这种关联是可以拆分而不是组合在一起的。
2.某一事件发生,需要向多方触发。
3.消息交换,如消息队列、事件总线的处理机制。

UML 类图

观察者模式.png

观察者模式主要角色:

  1. Subject:抽象主题,被观察者(Observable)的抽象,管理着众多观察者的实现,可以实现添加或删除观察者的功能。
  2. ConcreteSubject:具体主题,被观察者(Observable)的实现,通过该实现来向观察者发送通知。
  3. Observer:抽象观察者(Observer),观察者的抽象。一般是接口,实现该接口生成各种各样的观察者。
  4. ConcreteObserver:具体观察者,抽象观察者的具体实现,当被观察者发生变化时执行具体逻辑。

概念理解起来确实比较麻烦,但是结合具体的例子来理解的话会好很多,下面就是一个简单的例子。

二、观察者模式简单实现

要实现的功能:定义一个数据源,当数据源发生变化时,其它所有观察者收到消息并更新 UI。

具体步骤:
  1. 定义一个数据源 DataSource,继承 Observable。Observable 属于观察者模式中的抽象主题(Subject),那么这个实现类 DataSource 就是具体主题(ConcreteSubject)了。
    这个实现类的具体作用是作为被观察者,当它的数据发生变化时去通知所有观察者。
/**
 * 数据源,被观察者
 */
public class DataSource extends Observable {

    // 数据发生变化时调用该方法通知观察者
    public void updateData(String content){
        // 标记状态或内容已经发生改变
        setChanged();
        // 通知所有观察者
        notifyObservers(content);
    }

}
  • 首先定义一个更新数据的方法 updateData(),参数是可以被观察者接收的任意类型。
    这里定义的是 String 类型的,因为我的观察者是自定义 TextView,需要 String 来更新数据。
  • setChanged() 这个是父类 Observable 中的方法,用来改变一个标记,表明数据已经更新。后面会根据该标记来决定是否通知所有观察者。
  • notifyObservers(content)父类中的方法,该方法会调用所有观察者的 update() 方法实现数据的传递更新。
  1. 定义观察者 MyTextView,这是我自己定义的 TextView,实现了 Observer 接口。
    Observer 接口就是抽象观察者了,那么这里的实现类 MyTextView 就是具体观察者角色(ConcreteObserver)了
/**
 * 观察者,自定义 TextView,监听数据变化
 */

public class MyTextView extends TextView implements Observer {

    // 自定义 View 三个构造函数
    public MyTextView(Context context) {
        this(context,null);
    }

    public MyTextView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs,0);
    }

    public MyTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }
    // 父类 Observer 中的方法,当调用 notifyObservers 时调用
    @Override
    public void update(Observable o, Object arg) {
        setText(arg.toString());
    }
}
  • 自定义 TextView,三个构造函数不多说。
  • update(Observable o, Object arg) 方法是接口 Observer 中的方法,参数 Observable o 是具体的观察者类,Object arg是具体的数据。
  1. 定义 ObserverTestActivity,布局中写个 Button 模拟数据发生变化。接着使用刚才自定义的 MyTextView,这里写了两个。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.sky.viewtest.ObserverTestActivity">

    <Button
        android:id="@+id/btn_change"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="数据变化"/>

    <com.sky.viewtest.design_pattern.MyTextView
        android:id="@+id/tv_text1"
        android:layout_width="match_parent"
        android:layout_height="30dp"
        android:gravity="center"/>

    <com.sky.viewtest.design_pattern.MyTextView
        android:id="@+id/tv_text2"
        android:layout_width="match_parent"
        android:gravity="center"
        android:layout_height="30dp" />

</LinearLayout>
  1. 模拟数据变化并通知 UI。
public class ObserverTestActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_observer);
        // 模拟数据变化
        findViewById(R.id.btn_change).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                changeData();
            }
        });
    }

    private void changeData(){
        // 创建具体的被观察者类实例
        DataSource dataSource = new DataSource();

        MyTextView myTextView1 = (MyTextView) findViewById(R.id.tv_text1);
        MyTextView myTextView2 = (MyTextView) findViewById(R.id.tv_text2);
        // 添加观察者
        dataSource.addObserver(myTextView1);
        dataSource.addObserver(myTextView2);
        // 通知所有观察者数据更新
        dataSource.updateData("数据变化啦");
    }

}
  • 要注意的是只有把所有被观察者使用 addObserver() 添加进来才会收到后续数据更新。
效果:

当我点击按钮时,两个 TextView 的数据都发生了变化。


Test.png
三、源码分析

结合上文例子分析 java.util 包下的 Observer 和 Observable 的实现。

接口 Observer

public interface Observer {
    void update(Observable o, Object arg);
}
  • 很简单的一个接口,只定义了一个 update() 方法,参数 Observable 和 Object。
    Observable o 表示具体的被观察者对象,Object arg 是要传递和更新的数据。
  • 上文 MyTextView 实现该接口,并实现 update() 方法。该方法的作用是当 DataSource 发生数据变化时,会遍历所有已添加的 MyTextView 并调用它们的 update() 方法来更新 UI。
类 Observable

public class Observable {
    // 1.1 数据是否变化标记
    private boolean changed = false;
    // 1.2 长度自增长数组
    private Vector<Observer> obs;

    /** Construct an Observable with zero Observers. */
    
    public Observable() {
        obs = new Vector<>();
    }
    // 2.1 添加观察者对象
    public synchronized void addObserver(Observer o) {
        if (o == null)
            throw new NullPointerException();
        if (!obs.contains(o)) {
            obs.addElement(o);
        }
    }
    // 2.2 删除观察者对象
    public synchronized void deleteObserver(Observer o) {
        obs.removeElement(o);
    }
    // 3.1 通知所有观察者
    public void notifyObservers() { 
        notifyObservers(null);
    }

    public void notifyObservers(Object arg) {
        Object[] arrLocal;
        // 线程同步
        synchronized (this) {
            // 3.2 获取是否发生变化的标记
            if (!hasChanged())
                return;
            // 3.3 转化为 Object 数组
            arrLocal = obs.toArray();
            // 重置标记
            clearChanged();
        }
        // 遍历所有观察者并调用其 update 方法
        for (int i = arrLocal.length-1; i>=0; i--)
            ((Observer)arrLocal[i]).update(this, arg);
    }
    // 删除所有观察者对象
    public synchronized void deleteObservers() {
        obs.removeAllElements();
    }
    // 设置标记为 true,表明数据发生了变化且已经通知过
    protected synchronized void setChanged() {
        changed = true;
    }
    // 清除标记,恢复默认状态
    protected synchronized void clearChanged() {
        changed = false;
    }
    // 获取标记
    public synchronized boolean hasChanged() {
        return changed;
    }
    // 获取观察者的数量
    public synchronized int countObservers() {
        return obs.size();
    }
}

该类比较简单,按注释顺序来看:

  1. 两个变量 changedobschanged是数据是否变化的标记,主要作用是避免重复通知观察者。obs是一个自增长的数组,用来存放具体的观察者对象,也就是实现了 Observer 的实现类。
    这里有一个知识点:设计模式的 依赖倒置原则:面向接口编程而不是面向具体对象编程。这个 obs 数组存放的是接口类型而不是某个具体实现类型表明了这一点。
  2. 添加和删除观察者对象的方法就是往数组 obs 添加和删除元素。
  3. 3.1notifyObservers() 通知所有观察者,可以看到该函数使用了 synchronized 保证线程安全,然后 hasChanged() 获取当前标记状态,如果标记为 false 则 return 不进行通知。
    3.2 那么这个标记什么时候才能为 true 呢?是在该类的子类中,也就是刚才例子中 DataSource 数据源类 updateData() 方法中首先调用 setChanged() 来设置标记为 true,表明数据即将进行更新。
    3.3 之后将数组 obs 转化为 Object 数组,设置标记为 false,然后遍历 obs 数组并调用所有元素的 update() 方法。也就是例子中所有添加进来的 MyTextView 对象的 update() 方法都会被调用,所有 MyTextView 的 text 发生变化。

到这里 Observer(抽象观察者) 和 Observable(抽象被观察者)已经分析的差不多了,那么再结合刚才的例子来总结一下:

  1. MyTextView 实现 Observer,是具体的观察者。实现方法 update() 来执行具体的逻辑。
  2. DataSource 继承 Observable,是具体的被观察者。通过 notifyObservers() 方法传递具体数据来实现通知所有观察者,传递的具体逻辑是在父类中实现的。
  3. Observable 作为抽象被观察者实现具体的数据传递逻辑,其内部维护了一个标记和具体观察者列表,当数据发生变化时遍历该列表并通过调用 update() 方法来通知具体观察者实现不同的逻辑。
四、观察者模式在 RecyclerView 中的体现

通过以上对观察者模式的了解,四个主要角色 抽象观察者、具体观察者、抽象被观察者和具体观察者 起到了重要作用,而他们的运作是通过三个重要方法 注册观察者、解除注册、发送通知,那么分析 RecyclerView 也要从这几点入手。

首先我们知道 RecyclerView 中使用了观察者模式(和 ListView 类似),也知道 notifyDataSetChanged() 起到通知界面刷新的功能,那么就从这个方法入手。

RecyclerView.Adapter<VH extends ViewHolder> # notifyDataSetChanged()

public abstract static class Adapter<VH extends RecyclerView.ViewHolder> {
    private final RecyclerView.AdapterDataObservable mObservable = new RecyclerView.AdapterDataObservable();
    ...
    public final void notifyDataSetChanged() {
        mObservable.notifyChanged();
    }
    ...
}

这个方法其实是在 RecyclerView 的内部静态抽象类 Adapter<VH extends ViewHolder> 中,可以看到 notifyDataSetChanged() 实际调用了 Adapter 的成员变量 mObservable 的 notifyChanged() 方法,该方法的实现暂且不管。这个变量 mObservable 命名方式很熟悉,那么就去看一下这个 AdapterDataObservable 类吧。

static class AdapterDataObservable extends Observable<AdapterDataObserver>

这个类继承了 Observable,看样子是一个被观察者实现类,为了验证一下,去看看 Observable 类。

类 Observable

package android.database;

import java.util.ArrayList;

/**
 * Provides methods for registering or unregistering arbitrary observers in an {@link ArrayList}.
 *
 * This abstract class is intended to be subclassed and specialized to maintain
 * a registry of observers of specific types and dispatch notifications to them.
 *
 * @param T The observer type.
 */
public abstract class Observable<T> {
    /**
     * The list of observers.  An observer can be in the list at most
     * once and will never be null.
     */
    protected final ArrayList<T> mObservers = new ArrayList<T>();

    /**
     * Adds an observer to the list. The observer cannot be null and it must not already
     * be registered.
     * @param observer the observer to register
     * @throws IllegalArgumentException the observer is null
     * @throws IllegalStateException the observer is already registered
     */
    public void registerObserver(T observer) {
        if (observer == null) {
            throw new IllegalArgumentException("The observer is null.");
        }
        synchronized(mObservers) {
            if (mObservers.contains(observer)) {
                throw new IllegalStateException("Observer " + observer + " is already registered.");
            }
            mObservers.add(observer);
        }
    }

    /**
     * Removes a previously registered observer. The observer must not be null and it
     * must already have been registered.
     * @param observer the observer to unregister
     * @throws IllegalArgumentException the observer is null
     * @throws IllegalStateException the observer is not yet registered
     */
    public void unregisterObserver(T observer) {
        if (observer == null) {
            throw new IllegalArgumentException("The observer is null.");
        }
        synchronized(mObservers) {
            int index = mObservers.indexOf(observer);
            if (index == -1) {
                throw new IllegalStateException("Observer " + observer + " was not registered.");
            }
            mObservers.remove(index);
        }
    }

    /**
     * Remove all registered observers.
     */
    public void unregisterAll() {
        synchronized(mObservers) {
            mObservers.clear();
        }
    }
}
  • 我特意把包名也贴出来了,它不是 java 里的 Observable,而是 Android 自己的实现。
  • protected final ArrayList<T> mObservers = new ArrayList<T>();:根据这个 ArrayList 可以看出该类维护了一个<T>类列表,那么这<T>类应该就是具体观察者了。
  • registerObserver()unregisterObserver()unregisterAll() 符合抽象被观察者管理具体观察者的逻辑,所以这个类就是抽象被观察者角色了。

这样就可以确定刚才 RecyclerView.AdapterDataObservable 是一个具体被观察者了。理一下现在得到的逻辑:

public class RecyclerView extends ViewGroup implements ScrollingView, NestedScrollingChild2 {
    // 为了方便理解我打乱了顺序,不要钻牛角尖
    // 1. AdapterDataObservable:具体被观察者   Observable:抽象被观察者
    static class AdapterDataObservable extends Observable<AdapterDataObserver> {
        //3.mObservable.notifyChanged()
        public void notifyChanged() {
            for (int i = mObservers.size() - 1; i >= 0; i--) {
                mObservers.get(i).onChanged();
            }
        }
    }
    ...
    public abstract static class Adapter<VH extends ViewHolder> {
        //2. 具体被观察者实例 mObservable
        private final AdapterDataObservable mObservable = new AdapterDataObservable();
        ...
        public final void notifyDataSetChanged() {
            mObservable.notifyChanged();
        }
    }
}
  1. RecyclerView 静态内部类 AdapterDataObservable 是具体被观察者,Observable 类是 抽象被观察者,他们管理着具体观察者
  2. Adapter 中持有具体被观察者实例 mObservable
  3. 我们调用 notifyDataSetChanged() 实际调用了 具体被观察者实例 mObservablenotifyChanged() 方法。

那么接下来分析一下 mObservable.notifyChanged(); 干了什么:

AdapterDataObservable # notifyChanged()

public void notifyChanged() {
    for (int i = mObservers.size() - 1; i >= 0; i--) {
        mObservers.get(i).onChanged();
    }
}

这个方法做的事情很简单,遍历 mObservers,获取其中的具体观察者并调用他们的 onChanged() 方法达到发送通知的目的。这个 mObservers 其实是一个 ArrayList,是由抽象被观察者(Observable)管理的列表,在刚才的 Observable 类中早就定义好了。

在这里找到了发送通知的方法,遍历所有的具体观察者并调用他们的 onChanged() 方法,那么再看一下 onChanged() 方法的实现:

public abstract static class AdapterDataObserver {
    public void onChanged() {
        // Do nothing
    }
    ...
}

可以看到是抽象类的空实现,那么就去找它的实现类,Ctrl+F 搜索 "extends AdapterDataObserver"。欧耶找到了,这就说明实现类也定义本类中。其实大多数实现类并不在本类中,这个小技巧也就是偶尔取巧用得上(#滑稽)。

类 RecyclerViewDataObserver

private class RecyclerViewDataObserver extends AdapterDataObserver {
    RecyclerViewDataObserver() {
    }

    @Override
    public void onChanged() {
        assertNotInLayoutOrScroll(null);
        mState.mStructureChanged = true;

        setDataSetChangedAfterLayout();
        if (!mAdapterHelper.hasPendingUpdates()) {
            requestLayout();
        }
    }
    ...
}

可以看到重写的 onChanged() 中调用了 requestLayout() 申请重新布局,至于怎样实现,感兴趣的同学可以参考我另一篇文章:

Android View:一条线理解 View 绘制流程

那么回到正题,RecyclerViewDataObserver 实现了抽象类 AdapterDataObserver 的方法并被具体被观察者调用通知。那么可以得出结论:AdapterDataObserver 是抽象观察者,抽象出各种通知方法。RecyclerViewDataObserver 是具体观察者,实现抽象观察者中的方法执行具体逻辑。

这样四个角色都找齐了,三个方法只找到了发送通知的。还差注册和解除观察者的方法,这两个方法在 setAdapter 中所体现:

RecyclerView # setAdapter()

public void setAdapter(Adapter adapter) {
    // bail out if layout is frozen
    setLayoutFrozen(false);
    setAdapterInternal(adapter, false, true);
    requestLayout();
}

注册和解除观察者实际是在 setAdapterInternal() 中:

RecyclerView # setAdapterInternal()

private final RecyclerViewDataObserver mObserver = new RecyclerViewDataObserver();

private void setAdapterInternal(Adapter adapter, boolean compatibleWithPrevious,
                                boolean removeAndRecycleViews) {
    //1.第一个 if 
    if (mAdapter != null) {
        mAdapter.unregisterAdapterDataObserver(mObserver);
        mAdapter.onDetachedFromRecyclerView(this);
    }
    if (!compatibleWithPrevious || removeAndRecycleViews) {
        removeAndRecycleViews();
    }
    mAdapterHelper.reset();
    final Adapter oldAdapter = mAdapter;
    mAdapter = adapter;
    //2.为新的 adapter 注册观察者 
    if (adapter != null) {
        adapter.registerAdapterDataObserver(mObserver);
        adapter.onAttachedToRecyclerView(this);
    }
    if (mLayout != null) {
        mLayout.onAdapterChanged(oldAdapter, mAdapter);
    }
    mRecycler.onAdapterChanged(oldAdapter, mAdapter, compatibleWithPrevious);
    mState.mStructureChanged = true;
    markKnownViewsInvalid();
}

上面的代码主要关注的是下面两点:

  1. 第一个 if 中如果 mAdapter 不为 null,也就是重新设置 RecyclerView 的 adapter 时先解除旧的观察者对象。
  2. 为新的 adapter 注册观察者。
  3. 注意这里传递的参数 mObserver 是 RecyclerViewDataObserver 类型的,这个类是具体观察者

mAdapter.unregisterAdapterDataObserver 旧的 adapter 解除注册,adapter.registerAdapterDataObserver(mObserver); 新的 adapter 注册具体观察者。

Adapter # registerAdapterDataObserver()、unregisterAdapterDataObserver()

public void unregisterAdapterDataObserver(AdapterDataObserver observer) {
    mObservable.unregisterObserver(observer);
}

public void registerAdapterDataObserver(AdapterDataObserver observer) {
    mObservable.registerObserver(observer);
}

可以看到解除和注册的方法是通过 Adapter 中保存的具体被观察者对象实例(mObservable)调用父类抽象被观察者(Observable)中的注册和解除观察者来完成的。

先看传递过来的参数类型是 AdapterDataObserver,也就是我们的抽象观察者,也就说明了抽象被观察者中维护的 ArrayList<T> mObservers 的这个 <T> 就是 AdapterDataObserver。而这个 ArrayList 具体保存的是 AdapterDataObserver 的实现类 RecyclerViewDataObserver。

这一块我表达的可能不够清晰,那么这里的逻辑再理清一下:

在 setAdapter() 的过程中,将具体观察者类的实例 mObserver 作为参数传递,用于设置具体的观察者。然后
调用 Adapter 中的 registerAdapterDataObserver(AdapterDataObserver observer) 方法进行注册,因为 mObserver 是 AdapterDataObserver 的子类实例,所以可以接收。
接着再通过 Adapter 中的 具体被观察者实例 mObservable 调用父类 Observable 中的注册和解除注册方法处理逻辑。

到这里就差不多完成了整个过程:

  • 抽象被观察者:Observable<T>
  • 具体被观察者:AdapterDataObservable
  • 抽象观察者:AdapterDataObserver
  • 具体观察者:RecyclerViewDataObserver
  • 注册:registerAdapterDataObserver()
  • 解除注册:unregisterAdapterDataObserver()
  • 发送消息:notifyDataSetChanged() --> mObservable.notifyChanged() --> mObservers.get(i).onChanged()
五、观察者模式其它实现

观察者模式除了上文 java 包中的实现外,还有其它实现方式。话说回来,只要大方向不错,根据实际需求去定制设计模式和代码或许更好。

这里记录一下百度百科中记录的观察者模式 Demo。

  1. 首先是抽象主题,被观察者抽象:
//被观察者(一个抽象类,方便扩展)
public abstract class Observable{
 
    public final ArrayList<Class<?>> obserList = new ArrayList<Class<?>>();
 
    /**AttachObserver(通过实例注册观察者)
    *<b>Notice:</b>obcan'tbenull,oritwillthrowNullPointerException
    **/
    public<T> void registerObserver(T ob){
        if(ob==null) throw new NullPointerException();
        this.registerObserver(ob.getClass());
    }
 
    /**
    *AttachObserver(通过Class注册观察者)
    *@paramcls
    */
    public void registerObserver(Class<?> cls){
        if(cls==null) throw new NullPointerException();
        synchronized(obserList){
            if(!obserList.contains(cls)){
                obserList.add(cls);
            }
        }
    }
 
    /**UnattachObserver(注销观察者)
    *<b>Notice:</b>
    *<b>ItreverseswithattachObserver()method</b>
    **/
    public<T>void unRegisterObserver(Tob){
        if(ob==null) throw new NullPointerException();
        this.unRegisterObserver(ob.getClass());
    }
 
    /**UnattachObserver(注销观察者,有时候在未获取到实例使用)
    *<b>Notice:</b>
    *<b>ItreverseswithattachObserver()method</b>
    **/
    public void unRegisterObserver(Class<?>cls){
        if(cls==null) throw new NullPointerException();
        synchronized(obserList){
            Iterator<Class<?>>iterator=obserList.iterator();
            while(iterator.hasNext()){
                if(iterator.next().getName().equals(cls.getName())){
                    iterator.remove();
                    break;
                }
            }
        }
    }
 
    /**detachallobservers*/
    public void unRegisterAll(){
        synchronized(obserList){
            obserList.clear();
        }
    }
 
    /**Ruturnthesizeofobservers*/
    public int countObservers(){
        synchronized(obserList){
            returnobserList.size();
        }
    }
 
    /**
    *notify all observer(通知所有观察者,在子类中实现)
    *@paramobjs
    */
    public abstract void notifyObservers(Object... objs);
 
    /**
    *notify one certain observer(通知某一个确定的观察者)
    *@paramcls
    *@paramobjs
    */
    public abstract void notifyObserver(Class<?> cls, Object... objs);
 
    /**
    *notifyonecertainobserver
    *@paramcls
    *@paramobjs
    */
    public abstract<T> void notifyObserver(T t, Object... objs);
}

从上面代码可以看出:

  • ArrayList<Class<?>> obserList:观察者列表,Observable 维护着所有抽象观察者。
  • registerObserver()unRegisterObserver():Observable 包含添加和移除观察者对象的方法。
  • notifyObservers():通知所有观察者的函数,可以自己实现来统一管理,也可以交给子类去实现。这里是抽象方法,由子类实现。
  1. 抽象观察者,定义更新方法
//观察者,需要用到观察者模式的类需实现此接口
public interface Observer{
    void update(Object...objs);
}
  1. 具体被观察者,继承 Observable 类。
//目标被观察者
public class ConcreteObservable extends Observable{
 
    private static ConcreteObservableinstance = null;
    private ConcreteObservable(){};
    public static synchronized ConcreteObservablegetInstance(){
        if(instance == null){
            instance=newConcreteObservable();
        }
        returninstance;
    }
 
    @Override
    public <T> void notifyObserver(T t, Object... objs){
        if(t == null) throw new NullPointerException();
        this.notifyObserver(t.getClass(), objs);
    }
 
    @Override
    public void notifyObservers(Object... objs){
        for(Class<?>cls : obserList){
            this.notifyObserver(cls, objs);
        }
    }
 
    //通过java反射机制实现调用
    @Override
    public void notifyObserver(Class<?>cls, Object...objs){
        if(cls == null) throw new NullPointerException();
        Method[] methods = cls.getDeclaredMethods();
        for(Method method : methods){
            if(method.getName().equals("update")){
                try{
                    method.invoke(cls,objs);
                    break;
                }catch(IllegalArgumentException e){
                    e.printStackTrace();
                }catch(IllegalAccessException e){
                    e.printStackTrace();
                }catch(InvocationTargetException e){
                    e.printStackTrace();
                }
            }
        }
    }
}
  • notifyObserver():实现父类抽象方法 notifyObserver(),遍历所有观察者,通过 java 反射机制调用具体观察中类的方法。
  1. 具体观察者类,需要添加到抽象被观察者维护的列表中。
//使用(实现Observer接口)
public class Text extends Activity implements Observer{
    publicvoidonCreate(...){
        ConcreteObservable.getInstance().registerObserver(Text.class);
        ....
    }
 
    //实现接口处理
    publicvoidupdate(Object...objs){
        //做操作,比如更新数据,更新UI等
    }
}
六、总结

综上,只有找到四个重要角色:抽象观察者、具体观察者、抽象被观察者和具体观察者,以及三个方法:注册解除注册发送通知,就可以理清观察者模式的应用了。

观察者模式的优点:

  • 解耦:
    观察者和被观察者之间建立的是一个抽象的耦合,被观察者并不需要了解每一个具体的观察者,但是可以通过共同的接口来控制它们。
  • 扩展性高:
    如果需要创建新的观察者,只需要实现观察者抽象接口即可。

观察者模式的缺点:

  • 效率问题:
    如果观察者数量过多,遍历并按顺序执行它们的方法会产生效率问题。或者某个观察者所执行的代码过于繁琐,影响其他观察者信息或数据的接收。

有关观察者模式的记录就先到这里,在学会这些知识后灵活运用才是最重要的。个人觉得没有最好的代码,只有最合适的代码。

参考资料:
《Android源码设计模式解析与实战》

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,012评论 4 359
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,589评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 106,819评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,652评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 51,954评论 3 285
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,381评论 1 210
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,687评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,404评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,082评论 1 238
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,355评论 2 241
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,880评论 1 255
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,249评论 2 250
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,864评论 3 232
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,007评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,760评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,394评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,281评论 2 259

推荐阅读更多精彩内容