设计模式--观察者模式

定义?
定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并自动更新。

观察者模式的作用是什么?
观察者模式的主要作用就是对象解耦,将观察者和被观察者完全隔离,只依赖于Observer和Observable抽象。

观察者模式的简单实现
很多技术网站支持用户邮箱订阅,每周发布周报后会将优质的内容推送给订阅用户。

    /**
     * 程序员是观察者
     */
    public class Coder implements Observer {

        public String name;

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

        @Override
        public void update(Observable observable, Object data) {
            System.out.print(name + data);
        }

        @Override
        public String toString() {
            return name;
        }
    }
    /**
     * 技术网站是被观察者,当它有更新时所有的观察者(程序员)都会接收到相应的通知
     */
    public class DevTechFrontier extends Observable {

        public void postNewPublication(String content) {
            //标示状态,内容发生改变
            setChanged();
            //通知所有的观察者
            notifyObservers();
        }
    }
    /**
     * 测试代码
     */
    public class Test {
        public  void main(String[] args) {
            //被观察者
            DevTechFrontier devTechFrontier=new DevTechFrontier();
            //观察者
            Coder coder1=new Coder("coder-1");
            Coder coder2=new Coder("coder-2");
            Coder coder3=new Coder("coder-3");
            //将观察者注册到列表中
            devTechFrontier.addObserver(coder1);
            devTechFrontier.addObserver(coder2);
            devTechFrontier.addObserver(coder3);

            //发布消息
            devTechFrontier.postNewPublication("新的一期技术周报发布了!");
        }
    }

输出结果:
coder-1,新的一期技术周报发布了!
coder-2,新的一期技术周报发布了!
coder-3,新的一期技术周报发布了!

可以看到,所有订阅的用户都收到了更新消息,一对多的订阅。
这里Observer是抽象的观察者,Coder是具体的观察者;Observable是抽象被观察者,DevTechFrontier 是具体的可观察对象。Coder是观察者,它们订阅了DevTechFrontier 这个具体的可观察对象,当DevTechFrontier 有更新时,会遍历所有的观察者Coder,然后给这些观察者发布一个更新消息,即调用Coder的update方法,这样就达到了一对多的通知功能。在这个通知过程中,通知系统都是依赖Observer和Observable这两个抽象类,因此,对于Coder和DevTechFrontier 完全没有耦合。

JDK中的Observer接口和Observable类实现
1.在Observer接口源代码中只声明一个update()方法

public interface Observer {
    void update(Observable var1, Object var2);
}

被观察者的对象当改变时调用这个方法。实现这个接口的类,可以作为观察者。

2.Observable类,被观察者,消息的发出者,继承此类可以扩展。

public class Observable {
    //观察者的集合
    List<Observer> observers = new ArrayList<Observer>();

    boolean changed = false;

    public Observable() {
    }

    public void addObserver(Observer observer) {
        if (observer == null) {
            throw new NullPointerException("observer == null");
        }
        synchronized (this) {
            if (!observers.contains(observer))
                observers.add(observer);
        }
    }

    protected void clearChanged() {
        changed = false;
    }

    public int countObservers() {
        return observers.size();
    }

    public synchronized void deleteObserver(Observer observer) {
        observers.remove(observer);
    }

    public synchronized void deleteObservers() {
        observers.clear();
    }

    public boolean hasChanged() {
        return changed;
    }

    public void notifyObservers() {
        notifyObservers(null);
    }

    //通知所有订阅此主题的观察者对象  
    @SuppressWarnings("unchecked")
    public void notifyObservers(Object data) {
        int size = 0;
        Observer[] arrays = null;
        //这里为啥要同步?
        //保证observers集合的数据唯一
        synchronized (this) {
            if (hasChanged()) {
                clearChanged();
                size = observers.size();
                arrays = new Observer[size];
                observers.toArray(arrays);
            }
        }
        //这里为什么没有同步?
        //观察者的updata操作可能是耗时操作
        if (arrays != null) {
            for (Observer observer : arrays) {
                observer.update(this, data);
            }
        }
    }

    protected void setChanged() {
        changed = true;
    }
} 

Android源码分析
ListView是Android中最重要的控件之一,而ListView最重要的一个功能是Adapter。通常,我们往ListView添加数据后,都会调用Adapter的notifyDataSetChange。下面对这个方法的源码进行分析。
notifyDataSetChange这个方法定义在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();
    }
}

接下来看mDataSetObservable.notifyChanged()的源码:

/**
*数据集观察者
*/
public class DataSetObservable extends Observable<DataSetObserver> {
    //调用每个观察者的onChanged方法来通知它们被观察者发生了变化
    public void notifyChanged() {
        synchronized(mObservers) {
            for (int i = mObservers.size() - 1; i >= 0; i--) {
                mObservers.get(i).onChanged();
            }
        }
    }
}

这部分代码很简单,就是在mDataSetObservable.notifyChanged()中遍历所有的观察者,并且调用它们的onChanged方法,从而告知观察者发生了变化。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值