zoukankan      html  css  js  c++  java
  • 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 = "尊敬的用户,您好!
    ";
            str += "您收藏的图书《" + status.getName() + "》降价了。
    ";
            str += "过去的价格是:" + status.getOldPrice() + "
    ";
            str += "现在的价格是:" + status.getNewPrice() + "
    ";
            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

  • 相关阅读:
    ubuntu 11.04 Gnome 恢复默认的任务栏面板
    (转载)学习腾讯的产品管理之道
    (转载)项目管理之外谈项目管理
    windows 下键盘映射
    该留意的文章
    一些常用的工具
    ubuntu 11.04 old sources.list
    一个css3流程导图
    echarts雷达图
    highcharts图表
  • 原文地址:https://www.cnblogs.com/qitian1/p/6463511.html
Copyright © 2011-2022 走看看