首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > 编程 >

OpenJDK源码研究札记(六)-观察者模式工具类(Observer和Observable)和应用示例

2013-10-27 
OpenJDK源码研究笔记(六)--观察者模式工具类(Observer和Observable)和应用示例本文主要讲解OpenJDK观察者

OpenJDK源码研究笔记(六)--观察者模式工具类(Observer和Observable)和应用示例

本文主要讲解OpenJDK观察者模式的2个工具类,java.util.Observer观察者接口,java.util.Observable被观察者基类。

然后,给出了一个常见的观察者应用示例。

Observer观察者接口

/** * 一个类可以实现Observer接口,当它想要得到“被观察者”对象变化通知的时候  */public interface Observer {    /**     * 当被观察的对象发生变化时,这个方法被调用。一个应用调用Observable对象的notifyObservers方法,去通知所有的观察者,   Observable对象发生了变化。     * @param   o     被观察的对象.     * @param   arg   传递给notifyObservers方法的参数.     */    void update(Observable o, Object arg);}


Observable被观察者基类

这个类代表一个可以观察的对象,或数据(在模型-视图范式中)。
它能够被继承去代表一个应用想要观察的对象。

一个observable对象可以有一个或多个观察者。
一个观察者可以是一个实现了Observer接口的对象。

当一个observable实例发生了变化,一个应用可以调用Observable的notifyObservers方法,去通知
它的观察者所发生的变化,通过调用观察者的update方法。

通知被传递的顺序是没有指定的。
在Observable类中的默认实现是,按注册顺序通知Observers。
但是子类可以改变这种顺序,使用没有保证的顺序,在分开的线程中传递通知,或者确保他们的子类遵循他们所选择的这个顺序。

注意:这个通知机制和线程没有任何关系,与Object对象的wait和notify机制没有任何关系。

当一个observable被新创建的时候,它的observer集合是空的。
两个observer被认为是同一个,当且仅当他们的equals方法比较返回true的时候。

public class Observable {    //该对象是否已经发生了变化,默认为false    private boolean changed = false;   //Vector是线程安全的,ArrayList是非线程安全的    private Vector obs;   //构造一个没有观察者的Observable对象     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);    }public void notifyObservers(Object arg) {        //一个临时的数组缓冲,用来作为当前观察者状态的快照        Object[] arrLocal;        synchronized (this) {             //我们不想要Observer 回调任何代码,在保持它的Monitor的时候。            //从Vector中提取Observable 和存储Observer的状态的代码需要同步,但是通知观察者却不需要。            //最坏的潜在竞争性条件结果是:            //1.一个新增加的观察者将会错误正在进行的通知            //2.一个最近被取消注册的观察者将会被错误的通知,当它不需要关心的时候            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();    }//表明Observable对象已经发生了变化protected synchronized void setChanged() {        changed = true;    }     //表明这个对象已经不再变化,或者说明已经通知到所有的观察者最近的一次变化。    protected synchronized void clearChanged() {        changed = false;    }    //测试该对象是否已经发生了变化。当且仅当setChanged方法比clearChanged方法调用的次数更多的时候,返回true。    public synchronized boolean hasChanged() {        return changed;    }       // 返回Observable对象的观察者的数量.    public synchronized int countObservers() {         return obs.size();    }}


代码示例

书,被观察者(或者称之为订阅主题)

import java.util.Observable;//书,被观察者(或者称之为订阅主题)public class Book extends Observable {    // 书的ID    private Integer id;    // 书名    private String name;    // 当前价格    private Double price;    // 当书的价格修改时,调用该方法    public void modifyPrice(Double newPrice) {        ChangeStatus status = null;        // 差值大于0.01,就认为价格放生了变化        if (Math.abs(newPrice - price) >= 0.01) {            setChanged();            status = new ChangeStatus();            status.setId(id);            status.setName(name);            status.setOldPrice(price);            status.setNewPrice(newPrice);        }        // 通知客户书已经降价        notifyObservers(status);    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public Double getPrice() {        return price;    }    public void setPrice(Double price) {        this.price = price;    }    public Integer getId() {        return id;    }    public void setId(Integer id) {        this.id = id;    }}


观察者:用户的邮箱

import java.util.Observable;import java.util.Observer;/** * 观察者:用户的邮箱 */public class BuyerEmail implements Observer {    // 该方法会被“被观察者的父类”即Observable调用    public void update(Observable o, Object arg) {        // 这里做具体的发电子邮件的程序        if (arg instanceof ChangeStatus) {            NotifyUtils.sendEmail((ChangeStatus) arg);        }    }}


观察者:用户的手机

import java.util.Observable;import java.util.Observer;/** * 观察者:用户的手机 */public class BuyerMobile implements Observer {    // 该方法会被“被观察者的父类”即Observable调用    public void update(Observable o, Object arg) {        // 这里做具体的发电子邮件的程序        if(arg instanceof ChangeStatus){            NotifyUtils.sendSMS((ChangeStatus)arg);        }    }}


一本书的信息变化的实体类

public class ChangeStatus {    //书的ID    private Integer id;    //书名    private String name;    //过去的价格    private Double oldPrice;    //最新的价格    private Double newPrice;    public Integer getId() {        return id;    }    public void setId(Integer id) {        this.id = id;    }    public Double getOldPrice() {        return oldPrice;    }    public void setOldPrice(Double oldPrice) {        this.oldPrice = oldPrice;    }    public Double getNewPrice() {        return newPrice;    }    public void setNewPrice(Double newPrice) {        this.newPrice = newPrice;    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }}


发送通知的工具类

public class NotifyUtils {    // 发送邮件通知用户    public static void sendEmail(ChangeStatus status) {        print(status);    }    // 发送短信通知用户    public static void sendSMS(ChangeStatus status) {        print(status);    }    // 一种只是用来作为“演示”的发送信息的方法    private static void print(ChangeStatus status) {        println("*******************************************************");        String messageContent = messageContent(status);        println(messageContent);        println("********************************************************");    }    private static String messageContent(ChangeStatus status) {        // 一般,降价才会通知,这里只当是降价了        String str = "尊敬的用户,您好!\n";        str += "您收藏的图书《" + status.getName() + "》降价了。\n";        str += "过去的价格是:" + status.getOldPrice() + "\n";        str += "现在的价格是:" + status.getNewPrice() + "\n";        str += "您可以通过以下链接 http://blog.csdn.net/FansUnion 进行购买。";        return str;    }    private static void println(Object content) {        System.out.println(content);    }}


程序入口

public class ObserverPatternTest {    /**     * 观察者模式-用法示例     */    public static void main(String[] args) {        Book book = new Book();        book.setName("中国象棋程序的设计与实现");        book.setPrice(45.0);        // 下面的观察者在实际应用中可以从数据库或文件中读取        BuyerEmail email = new BuyerEmail();        BuyerMobile mobile = new BuyerMobile();        // 增加观察者,在实际应用中就是哪些人对该书作了关注        book.addObserver(email);        book.addObserver(mobile);        book.modifyPrice(34.00);    }}


输出结果

*******************************************************
尊敬的用户,您好!
您收藏的图书《中国象棋程序的设计与实现》降价了。
过去的价格是:45.0
现在的价格是:34.0
您可以通过以下链接 http://blog.csdn.net/FansUnion 进行购买。
********************************************************
*******************************************************
尊敬的用户,您好!
您收藏的图书《中国象棋程序的设计与实现》降价了。
过去的价格是:45.0
现在的价格是:34.0
您可以通过以下链接 http://blog.csdn.net/FansUnion 进行购买。
********************************************************

参考资料:OpenJDK7源码

原文参见: http://FansUnion.cn/articles/2936

热点排行