观察者模式

来源:互联网 发布:北京大学软件共享平台 编辑:程序博客网 时间:2024/06/06 06:39

观察者模式

简介:

出版者+订阅者=观察者模式

 Subject

    主题接口,也即可观察者(Observable),对象使用此接口注册为观察者,或者把自己从观察着中删除。每个主题可以有多个观察者。

    ConcreteSubject

    一个具体主题实现了主题接口,除了注册和撤销之外,具体主题还实现了notifyObservers()方法,这个方法用来在主题状态改变时更行所有的观察者。具体主题也可能有设置和获取状态的方法。

    Observer

    所有潜在的观察者必须实现观察者接口,这个接口只有update()方法,当主题改变时,它被调用。

    ConcreteObserver

    具体的观察者可以是任何实现了Observer接口的类。观察者必须注册具体主题,一边接收更新。

    基本原则:为了交互对象之间的松耦合设计而努力

    观察者模式的定义:观察者模式定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有的依赖者都会收到通知并自动更新。

    观察者模式中,一对多的关系体现在哪里?

    这个模式中,主题是具有状态的对象,并且可以控制这个状态,也就是说,是一个具有状态的主题。

    另一方面,观察者使用这些状态,虽然这些状态并不属于他们。有多个观察者,依靠主题来告诉他们主题状态何时变了。

    这就产生了一个关系,一个主题对多个观察者的关系

    松耦合设计威力体现在哪里?

    当两个对象松耦合,他们依然可以交互,但是不太清楚彼此的细节。观察者模式提供了一种对象设计,让主题和观察者松耦合。

    

类图:

实例:

主题1:游戏新闻对象:GameMsg

package com.mylearn.designmodel.observer;

import java.util.Observable;

/**

 * Created by IntelliJ IDEA.

 * User: yingkuohao

 * Date: 13-10-31

 * Time: 上午11:58

 * CopyRight:360buy

 * Descrption:

 * To change this template use File | Settings | File Templates.

 */

public class GameMsg extends Observable {

    private String msg;

    private static String flag = "game";

    public String getMsg() {

        return msg;

    }

    public void setMsg(String msg) {

        this.msg = msg;

        sendMsg();

    }

    private void sendMsg() {

        super.setChanged();  //开关

        super.notifyObservers(); //通知消费者

    }

}

主题2:头条新闻对象:HeadMsg

package com.mylearn.designmodel.observer;

import java.util.Observable;

/**

 * Created by IntelliJ IDEA.

 * User: yingkuohao

 * Date: 13-10-31

 * Time: 上午11:58

 * CopyRight:360buy

 * Descrption:

 * To change this template use File | Settings | File Templates.

 */

public class HeadMsg extends Observable {

    private String msg;

    private static String flag = "head";

    public String getMsg() {

        return msg;

    }

    public void setMsg(String msg) {

        this.msg = msg;

        sendMsg();

    }

    private void sendMsg() {

        super.setChanged();

        super.notifyObservers(); //通知消费者,notify方法将遍历Observable中的Vector,找到其中的Observer,调用其update方法。

    }

}

观察者A:只订阅游戏新闻

package com.mylearn.designmodel.observer;

import java.util.Observable;

import java.util.Observer;

/**

 * Created by IntelliJ IDEA.

 * User: yingkuohao

 * Date: 13-10-31

 * Time: 下午12:02

 * CopyRight:360buy

 * Descrption:

 * To change this template use File | Settings | File Templates.

 */

public class ObserverA implements Observer {

    private Observable observable;

    public Observable getObservable() {

        return observable;

    }

    public void setObservable(Observable observable) {

        this.observable = observable;

        observable.addObserver(this);   //加入观察者 ,Observable类中维护了一个Vector,用于保存注册的观察者信息,

    }

    /**

     * 相当于一个锚链接,当Observable中有新消息时,便会通知观察者,调用观察者的update方法。

     *

     * @param o

     * @param arg

     */

    public void update(Observable o, Object arg) {

        if (o instanceof GameMsg) {

            //主动拉消息

            String msg = ((GameMsg) o).getMsg();

            display(msg);

        }

    }

    public void display(String msg) {

        System.out.println("oyeget a game msg:" + msg);

    }

}

观察者B:只订阅头条新闻

package com.mylearn.designmodel.observer;

import java.util.Observable;

import java.util.Observer;

/**

 * Created by IntelliJ IDEA.

 * User: yingkuohao

 * Date: 13-10-31

 * Time: 下午12:02

 * CopyRight:360buy

 * Descrption:

 * To change this template use File | Settings | File Templates.

 */

public class ObserverB implements Observer {

    private Observable observable;

    public Observable getObservable() {

        return observable;

    }

    public void setObservable(Observable observable) {

        this.observable = observable;

        observable.addObserver(this);  //加入观察者

    }

    public void update(Observable o, Object arg) {

        if (o instanceof HeadMsg) {

            String msg = ((HeadMsg) o).getMsg();

            display(msg);

        }

    }

    public void display(String msg) {

        System.out.println("oyeget a head msg:" + msg);

    }

}

Test类:

package com.mylearn.designmodel.observer;

/**

 * Created by IntelliJ IDEA.

 * User: yingkuohao

 * Date: 13-10-31

 * Time: 下午12:06

 * CopyRight:360buy

 * Descrption:

 * To change this template use File | Settings | File Templates.

 */

public class Test {

    public static void main(String args[]) {

      GameMsg gameMsg =new GameMsg();

        HeadMsg headMsg =new HeadMsg();

        ObserverA observerA =new ObserverA();

        ObserverB observerB =new ObserverB();

        observerA.setObservable(gameMsg);

        observerB.setObservable(headMsg);

        gameMsg.setMsg("dota 更新了!");

        headMsg.setMsg("普京当选了!");

    }

}

源码:

Observable类:抽象主题对象(即被观察者的父类)

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(Object arg) {

/*

         * a temporary array buffer, used as a snapshot of the state of

         * current Observers.

         */

        Object[] arrLocal;

synchronized (this) {

    /* We don't want the Observer doing callbacks into

     * arbitrary code while holding its own Monitor.

     * The code where we extract each Observable from 

     * the Vector and store the state of the Observer

     * needs synchronization, but notifying observers

     * does not (should not).  The worst result of any 

     * potential race-condition here is that:

     * 1) a newly-added Observer will miss a

     *   notification in progress

     * 2) a recently unregistered Observer will be

     *   wrongly notified when it doesn't care

     */

    if (!changed)

                return;

            arrLocal = obs.toArray();

            clearChanged(); // 当一个主题执行notify方法时,会把changed设为false,这样其他线程就会进不来,除非其他线程执行了setChange方法,所以,我们的实例中调用notify方法时都要先改变changed状态

        }

        //遍历观察者集合,分别执行callback方法,即update方法,这个是由我们的Observer接口约定的

        for (int i = arrLocal.length-1; i>=0; i--)

            ((Observer)arrLocal[i]).update(this, arg);

    }

//由此可以看到我们的notify方法跟Objectnotify,wait一点关系都没有,只不过是方法的回调。

优点:

主题和观察者之间解耦,主题不用知道具体的观察者是谁,当新加观察者或删除观察者时,主题不用做任何改动,主题和观察者都是可插拔的。

缺点:

1. Observable是一个类而不是一个接口,无法实现多继承。

2. Observable把很多方法如setChanged方法保护起来,我们无法用聚合的方式把Observable聚合到自己定义的对象中来,违反了“多用组合,少用继承”的原则。

原创粉丝点击