您的位置:首页 > 编程语言 > Java开发

一个简易的java自带的观察者模式实现

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

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


J***A提供的对观察者模式的支持

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


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()方法,从而使所有的观察者都被通知更新自己。
下面是我写的一个简单的观察者模式的实现,这里用milk表示牛奶订购者,模拟观察者对象Observer,用milkShop表示牛奶店,模拟被观察者对象(主题对象),模拟逻辑是牛奶订购者向牛奶店订购牛奶,当牛奶店有新的牛奶到货就通知订购者。
public class Milk implements Observer{
	public String Num;
	/*
	 * update是Observer的实现方法arg1是subject传回的结果数据,这里可以主动获取,也可以获取数据为标志,然后再拉取
	   (non-Javadoc)
	 * @see java.util.Observer#update(java.util.Observable, java.lang.Object)
	 */
    public void update(Observable arg0, Object arg1) {
		// TODO Auto-generated method stub
		
		Num=(String )arg1;
		System.out.println("********************"+Num);
	}

}
被观察者的代码如下
public class MilkShop extends Observable{
	
	public String Num;

	public String getNum() {
		return Num;
	}

	public void setNum(String num) {
		Num = num;
		DateChange();
	}
	/*
	 * 数据变化,通知注册在他这里的观察者,并且把数据传给观察者
	 */

	 
    public void  DateChange(){
    	
    	this.setChanged();
    	this.notifyObservers(Num);
    	
    }	

}
测试类的代码如下
public class TestObserver {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
              Milk mMilk=new Milk();
              MilkShop mMilkShop=new MilkShop();
              /*
              * subject添加观察者,
              */
              mMilkShop.addObserver(mMilk);
              /*
               * 模拟subject数据变化,然后通知观察者数据变化,并且将数据传给观察者
               */
             mMilkShop.setNum("27");
	}

}
然后输出结果如下:
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: