关于观察者模式的介绍以及安卓中的使用

来源:互联网 发布:搜索软件 编辑:程序博客网 时间:2024/05/20 23:07

观察者模式是对象的行为模式,又叫发布-订阅(Publish/Subscribe)模式、模型-视图(Model/View)模式、源-监听器(Source/Listener)模式或从属者(Dependents)模式。

  观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态上发生变化时,会通知所有观察者对象,使它们能够自动更新自己。


观察者模式的结构

  一个软件系统里面包含了各种对象,就像一片欣欣向荣的森林充满了各种生物一样。在一片森林中,各种生物彼此依赖和约束,形成一个个生物链。一种生物的状态变化会造成其他一些生物的相应行动,每一个生物都处于别的生物的互动之中。

  同样,一个软件系统常常要求在某一个对象的状态发生变化的时候,某些其他的对象做出相应的改变。做到这一点的设计方案有很多,但是为了使系统能够易于复用,应该选择低耦合度的设计方案。减少对象之间的耦合有利于系统的复用,但是同时设计师需要使这些低耦合度的对象之间能够维持行动的协调一致,保证高度的协作。观察者模式是满足这一要求的各种设计方案中最重要的一种。

  下面以一个简单的示意性实现为例,讨论观察者模式的结构。

  观察者模式所涉及的角色有:

  ●  抽象主题(Subject)角色:抽象主题角色把所有对观察者对象的引用保存在一个聚集(比如ArrayList对象)里,每个主题都可以有任何数量的观察者。抽象主题提供一个接口,可以增加和删除观察者对象,抽象主题角色又叫做抽象被观察者(Observable)角色。

  ●  具体主题(ConcreteSubject)角色:将有关状态存入具体观察者对象;在具体主题的内部状态改变时,给所有登记过的观察者发出通知。具体主题角色又叫做具体被观察者(Concrete Observable)角色。

  ●  抽象观察者(Observer)角色:为所有的具体观察者定义一个接口,在得到主题的通知时更新自己,这个接口叫做更新接口。

  ●  具体观察者(ConcreteObserver)角色:存储与主题的状态自恰的状态。具体观察者角色实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题的状态 像协调。如果需要,具体观察者角色可以保持一个指向具体主题对象的引用。

  源代码

    抽象主题角色类

复制代码
public abstract class Subject {    /**     * 用来保存注册的观察者对象     */    private    List<Observer> list = new ArrayList<Observer>();    /**     * 注册观察者对象     * @param observer    观察者对象     */    public void attach(Observer observer){                list.add(observer);        System.out.println("Attached an observer");    }    /**     * 删除观察者对象     * @param observer    观察者对象     */    public void detach(Observer observer){                list.remove(observer);    }    /**     * 通知所有注册的观察者对象     */    public void nodifyObservers(String newState){                for(Observer observer : list){            observer.update(newState);        }    }}
复制代码

  具体主题角色类

复制代码
public class ConcreteSubject extends Subject{        private String state;        public String getState() {        return state;    }    public void change(String newState){        state = newState;        System.out.println("主题状态为:" + state);        //状态发生改变,通知各个观察者        this.nodifyObservers(state);    }}
复制代码

  抽象观察者角色类

复制代码
public interface Observer {    /**     * 更新接口     * @param state    更新的状态     */    public void update(String state);}
复制代码

  具体观察者角色类

复制代码
public class ConcreteObserver implements Observer {    //观察者的状态    private String observerState;        @Override    public void update(String state) {        /**         * 更新观察者的状态,使其与目标的状态保持一致         */        observerState = state;        System.out.println("状态为:"+observerState);    }}
复制代码

  在运行时,这个客户端首先创建了具体主题类的实例,以及一个观察者对象。然后,它调用主题对象的attach()方法,将这个观察者对象向主题对象登记,也就是将它加入到主题对象的聚集中去。

  这时,客户端调用主题的change()方法,改变了主题对象的内部状态。主题对象在状态发生变化时,调用超类的notifyObservers()方法,通知所有登记过的观察者对象。

JAVA提供的对观察者模式的支持

  在JAVA语言的java.util库里面,提供了一个Observable类以及一个Observer接口,构成JAVA语言对观察者模式的支持。

  Observer接口

  这个接口只定义了一个方法,即update()方法,当被观察者对象的状态发生变化时,被观察者对象的notifyObservers()方法就会调用这一方法。

public interface Observer {    void update(Observable o, Object arg);}

  Observable类

  被观察者类都是java.util.Observable类的子类。java.util.Observable提供公开的方法支持观察者对象,这些方法中有两个对Observable的子类非常重要:一个是setChanged(),另一个是notifyObservers()。第一方法setChanged()被调用之后会设置一个内部标记变量,代表被观察者对象的状态发生了变化。第二个是notifyObservers(),这个方法被调用时,会调用所有登记过的观察者对象的update()方法,使这些观察者对象可以更新自己。

复制代码
public class Observable {    private boolean changed = false;    private Vector obs;       /** Construct an Observable with zero Observers. */    public Observable() {    obs = new Vector();    }    /**     * 将一个观察者添加到观察者聚集上面     */    public synchronized void addObserver(Observer o) {        if (o == null)            throw new NullPointerException();    if (!obs.contains(o)) {        obs.addElement(o);    }    }    /**     * 将一个观察者从观察者聚集上删除     */    public synchronized void deleteObserver(Observer o) {        obs.removeElement(o);    }    public void notifyObservers() {    notifyObservers(null);    }    /**     * 如果本对象有变化(那时hasChanged 方法会返回true)     * 调用本方法通知所有登记的观察者,即调用它们的update()方法     * 传入this和arg作为参数     */    public void notifyObservers(Object arg) {        Object[] arrLocal;    synchronized (this) {        if (!changed)                return;            arrLocal = obs.toArray();            clearChanged();        }        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;    }    /**     * 将“已变化”重置为false     */    protected synchronized void clearChanged() {    changed = false;    }    /**     * 检测本对象是否已变化     */    public synchronized boolean hasChanged() {    return changed;    }    /**     * Returns the number of observers of this <tt>Observable</tt> object.     *     * @return  the number of observers of this object.     */    public synchronized int countObservers() {    return obs.size();    }}
复制代码

  这个类代表一个被观察者对象,有时称之为主题对象。一个被观察者对象可以有数个观察者对象,每个观察者对象都是实现Observer接口的对象。在被观察者发生变化时,会调用Observable的notifyObservers()方法,此方法调用所有的具体观察者的update()方法,从而使所有的观察者都被通知更新自己。

怎样使用JAVA对观察者模式的支持

  这里给出一个非常简单的例子,说明怎样使用JAVA所提供的对观察者模式的支持。在这个例子中,被观察对象叫做Watched;而观察者对象叫做Watcher。Watched对象继承自java.util.Observable类;而Watcher对象实现了java.util.Observer接口。另外有一个Test类扮演客户端角色。

  源代码

  被观察者Watched类源代码

复制代码
public class Watched extends Observable{        private String data = "";        public String getData() {        return data;    }    public void setData(String data) {                if(!this.data.equals(data)){            this.data = data;            setChanged();        }        notifyObservers();    }        }
复制代码

  观察者类源代码

复制代码
public class Watcher implements Observer{        public Watcher(Observable o){        o.addObserver(this);    }        @Override    public void update(Observable o, Object arg) {                System.out.println("状态发生改变:" + ((Watched)o).getData());    }}
复制代码

  测试类源代码

复制代码
public class Test {    public static void main(String[] args) {                //创建被观察者对象        Watched watched = new Watched();        //创建观察者对象,并将被观察者对象登记        Observer watcher = new Watcher(watched);        //给被观察者状态赋值        watched.setData("start");        watched.setData("run");        watched.setData("stop");    }}

在Android中最常用的应用:

在ListView中Adapter中favoritesAdapter.registerDataSetObserver(mDataSetObserver);;数据改变之后会自动调用:

mDataSetObserver里面的方法;如:

[html] view plain copy
  1. DataSetObserver mDataSetObserver = new DataSetObserver() {  
  2.   
  3.         @Override  
  4.         public void onChanged() {  
  5.             if (favoritesAdapter.getCount() <= 0) {  
  6.                 showNoDeviceHint();  
  7.             } else {  
  8.                 hiddenNoDeviceHint();  
  9.             }  
  10.             loadingImageButton.setVisibility(View.GONE);  
  11.             super.onChanged();  
  12.         }  
  13.   
  14.         @Override  
  15.         public void onInvalidated() {  
  16.             super.onInvalidated();  
  17.         }  
  18.   
  19.     };  



0 0
原创粉丝点击