设计模式理解之观察者模式

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Kikitious_Du/article/details/78809985

简    介


定义:定义对象间的一种一对多的依赖关系,使得每当一个对象的状态发生变化时,其相关依赖的对象都会得到通知并被自动更新。

观察者模式是一种对象行为型模式。可以看做是一种通知机制,实现一处通知,多处更新。

别名:发布-订阅模式、源-监听器模式、从属者模式等。


观察者模式的结构


4个角色:

● Subject 目标,即被观察者,提供 添加观察者对象、删除观察者对象、调用观察者对象的方法 的接口,通常为抽象类

● Observer 观察者,提供 更新 的接口,通常为一个接口类,在Subject状态发生变化时,这个更新的方法就会被触发

● ConcreteSubject 具体目标,Subject的具体实现类。可在此类中定义具体的业务逻辑

● ConcreteObserver 具体观察者,Observer的具体实现类。实现收到Subject状态变化信号后要处理的具体逻辑


实现步骤


我们来实现一个老师布置家庭作业给学生的例子,每当老师布置一个作业,所有的学生就会得到通知。

● Observer 观察者

public interface Observer {
    void receiveHomework(String string);
}

● Subject 目标

public interface Subject {
    void addObserver(Observer observer);

    void removeObserver(Observer observer);

    void notifyObservers();
}

● ConcreteSubject 具体目标

public class Teacher implements Subject {

    private List<Observer> observers = new ArrayList<>();

    private String info;

    @Override
    public void addObserver(Observer observer) {
        observers.add(observer);
    }

    @Override
    public void removeObserver(Observer observer) {
        observers.remove(observer);
    }

    @Override
    public void notifyObservers() {
        for (Observer observer : observers) {
            observer.receiveHomework(getInfo());
        }
    }

    public String getInfo() {
        return info;
    }

    public void publishHomeWork(String info) {
        this.info = info;
        System.out.println("This is the homework: " + info);
        this.notifyObservers();
    }
}

● ConcreteObserver 具体观察者

public class Student implements Observer {

    private String name;
    private String studentId;
    private Teacher teacher;

    public Student(String name, String id, Teacher teacher) {
        this.name = name;
        this.studentId = id;
        this.teacher = teacher;
        teacher.addObserver(this);
    }


    @Override
    public void receiveHomework(String string) {
        System.out.println(name + "收到了作业:" + string);
    }
}
测试一下哈

public class Test {

    public static void main(String[] args) {
        Teacher teacher = new Teacher();

        Student katherine = new Student("Katherine", "101", teacher);
        Student bob = new Student("Bob", "102", teacher);
        Student tom = new Student("Tom", "103", teacher);
        teacher.publishHomeWork("数学课本第5页习题3");
        teacher.publishHomeWork("数学课本第7页习题1");

        teacher.removeObserver(bob);
        teacher.publishHomeWork("数学课本第9页习题3");
    }
}
//This is the homework: 数学课本第5页习题3
//Katherine收到了作业:数学课本第5页习题3
//Bob收到了作业:数学课本第5页习题3
//Tom收到了作业:数学课本第5页习题3
//This is the homework: 数学课本第7页习题1
//Katherine收到了作业:数学课本第7页习题1
//Bob收到了作业:数学课本第7页习题1
//Tom收到了作业:数学课本第7页习题1
//This is the homework: 数学课本第9页习题3
//Katherine收到了作业:数学课本第9页习题3
//Tom收到了作业:数学课本第9页习题3


Java中内置的观察者模式


import java.util.Observable;//抽象类
import java.util.Observer;//接口
我们实现一个书店通知读者来新书的例子,即读者观察书店的情况。

● 具体目标继承Observable抽象类

public class BookStore extends Observable {

    private String info;

    public String getInfo() {
        return info;
    }

    public void pushlishBookInfo(String info) {
        this.info = info;
        System.out.println("书店出了新书:" + info);
        setChanged();//目标发通知之前,先调用setChanged()方法,标志状态改变
        notifyObservers();//发出通知,所有观察者收到通知
    }
}
● 观察者实现Observer接口

public class Reader implements Observer {

    private BookStore store;
    private String name;

    public Reader(BookStore store, String name) {
        this.store = store;
        this.name = name;
        this.store.addObserver(this);//调用addObserver(Observer o)进行添加观察者
    }

    @Override
    public void update(Observable o, Object arg) {
        System.out.println(name + "收到了" + ((BookStore) o).getInfo() + "的信息");
    }
}
● 测试

public class Test {

    public static void main(String[] args) {
        BookStore store = new BookStore();
        Reader reader1 = new Reader(store, "Katherine");
        Reader reader2 = new Reader(store, "Bob");
        store.pushlishBookInfo("奇特的一生");
    }
}
//书店出了新书:奇特的一生
//Bob收到了奇特的一生的信息
//Katherine收到了奇特的一生的信息

Android源码ListView的观察者模式分析


先来对号入座一下,再一起分析

● Observable<T>--------------Subject 目标

● DataSetObserver-------------Observer 观察者

● DataSetObservable----------ConcreteSubject 具体目标

● AdapterDataSetObserver----ConcreteObserver 具体观察者


● Observable<T>泛型的抽象类,提供了注册、撤销(一个或者全部)的接口。

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

DataSetObservable,提供了通知各个Observer的方法。

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

    /**
     * Invokes {@link DataSetObserver#onInvalidated} on each observer.
     * Called when the data set is no longer valid and cannot be queried again,
     * such as when the data set has been closed.
     */
    public void notifyInvalidated() {
        synchronized (mObservers) {
            for (int i = mObservers.size() - 1; i >= 0; i--) {
                mObservers.get(i).onInvalidated();
            }
        }
    }
}
● DataSetObserver,提供了更新通知的接口

public abstract class DataSetObserver {
    /**
     * This method is called when the entire data set has changed,
     * most likely through a call to {@link Cursor#requery()} on a {@link Cursor}.
     */
    public void onChanged() {
        // Do nothing
    }

    /**
     * This method is called when the entire data becomes invalid,
     * most likely through a call to {@link Cursor#deactivate()} or {@link Cursor#close()} on a
     * {@link Cursor}.
     */
    public void onInvalidated() {
        // Do nothing
    }
}
● AdapterDataSetObserver,实现了onChanged()方法和onInvalidated()方法

    class AdapterDataSetObserver extends DataSetObserver {

        private Parcelable mInstanceState = null;

        @Override
        public void onChanged() {
            mDataChanged = true;
            mOldItemCount = mItemCount;
            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();
            requestLayout();
        }

        @Override
        public void onInvalidated() {
            mDataChanged = true;

            if (AdapterView.this.getAdapter().hasStableIds()) {
                // Remember the current state for the case where our hosting activity is being
                // stopped and later restarted
                mInstanceState = AdapterView.this.onSaveInstanceState();
            }

            // Data is invalid so we should reset our state
            mOldItemCount = mItemCount;
            mItemCount = 0;
            mSelectedPosition = INVALID_POSITION;
            mSelectedRowId = INVALID_ROW_ID;
            mNextSelectedPosition = INVALID_POSITION;
            mNextSelectedRowId = INVALID_ROW_ID;
            mNeedSync = false;

            checkFocus();
            requestLayout();
        }

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

我们来看看ListView的setAdapter(ListAdapter adapter)方法,假设我们给这个方法传了BaseAdapter的子类对象,BaseAdapter的源码如下

//BaseAdapter实现了ListAdapter的接口,然后关联了DataSetObserver的注册、撤销、通知等方法
//所以这里就相当于Subject。。。
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);
    }
    
    /**
     * Notifies the attached observers that the underlying data has been changed
     * and any View reflecting the data set should refresh itself.
     */
    public void notifyDataSetChanged() {
        mDataSetObservable.notifyChanged();
    }

    /**
     * Notifies the attached observers that the underlying data is no longer valid
     * or available. Once invoked this adapter is no longer valid and should
     * not report further data set changes.
     */
    public void notifyDataSetInvalidated() {
        mDataSetObservable.notifyInvalidated();
    }

    public boolean areAllItemsEnabled() {
        return true;
    }

    public boolean isEnabled(int position) {
        return true;
    }

    public View getDropDownView(int position, View convertView, ViewGroup parent) {
        return getView(position, convertView, parent);
    }

    public int getItemViewType(int position) {
        return 0;
    }

    public int getViewTypeCount() {
        return 1;
    }
    
    public boolean isEmpty() {
        return getCount() == 0;
    }
}

那我们使用ListView的setAdapter(ListAdapter adapter)方法的时候,ListView就new出了一个观察者对象,并且进行了注册。

    public void setAdapter(ListAdapter adapter) {
        if (mAdapter != null && mDataSetObserver != null) {
            mAdapter.unregisterDataSetObserver(mDataSetObserver);
        }

        resetList();
        mRecycler.clear();

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

        ......

        if (mAdapter != null) {
            ......

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

            ......
            }
        } else {
            mAreAllItemsSelectable = true;
            checkFocus();
            // Nothing selected
            checkSelectionChanged();
        }

        requestLayout();
    }

当ListView的数据产生改变时,我们会调用adapter的notifyDataChanged()方法,然后这个方法会调用mDataSetObservable.notifyChanged()方法,即DataSetObservable的notifyChanged()方法,即AdapterDataSetObserver的onChanged()方法。进而完成刷新操作。


观察者模式的优缺点


优点:

观察者和目标之间是轻度的关联关系,且为抽象耦合,对于两者来说都比较容易扩展。

常用的触发机制,形成一条触发链。

缺点:

因为是触发链,所以当观察者比较多的时候,可能会产生性能问题。

在链式结构中,容易产生循环引用的错误,造成系统假死。



参考链接:

http://blog.csdn.net/fangchongbory/article/details/7774044

https://www.cnblogs.com/fingerboy/p/5468994.html

http://www.jianshu.com/p/d55ee6e83d66



微信公众号,一起来玩耍,纯属娱乐,哈哈哈~~~


猜你喜欢

转载自blog.csdn.net/Kikitious_Du/article/details/78809985
今日推荐