zoukankan      html  css  js  c++  java
  • 观察者模式 —— java.util.Observable + java.util.Observer 源码学习

    学习观察者模式,结合JavaJDK的内置观察者模式代码一起学习package java.util;


    //不是抽象类,也不是接口
    public class Observable { private boolean changed = false; //状态标志 private Vector<Observer> obs; //储存观察者的集合引用 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) {
          /*从集合中提取每个观察者的代码需要同步,但是通知观察者的代码不需要(不应该)。
            潜在的最坏的结果是:
            (1)新增的观察者错过了正在进行的通知
            (2)未注册的观察者被通知到了
         */
                if (!changed) //判断标志
                    return;
                arrLocal = obs.toArray(); //集合转化成数组
                clearChanged(); //标志恢复成false 不需要通知更新
            }
    
            for (int i = arrLocal.length-1; i>=0; i--)
                ((Observer)arrLocal[i]).update(this, arg);  //每个观察者的update方法需要的参数是两个,主题和参数
        }
    
        /**
         * 清除全部的观察者
         */
        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;
        }
    
        /*返回观察者的数量*/
        public synchronized int countObservers() {
            return obs.size();
        }
    }

    这个类的主要构成要点:

    1、包含所有观察者的(空)的集合 + 对这个集合的管理操作(增减,查看数量)

    2、包含一个(是否变动)标志 + 对这个标志的管理操作(设置、查看)

    3、向所有观察者发送通知

    继续学习观察者模式,JavaJDK中java.util.Observer源码学习:

    package java.util;
    
    /*这是观察者的接口,关键点就是它有一个update方法,每当被通知修改时候,就是这个方法被调用
     */
    public interface Observer {
        void update(Observable o, Object arg);
    }

    使用这两个内置的观察者模式类,参考方法:

    (1)新建一个具体主题类继承Observable,  不需要重写它的任何方法,只要添加自己需要的业务逻辑: 设置传递的参数信息,发送消息的方法……

      唯一需要注意的是:两种通知方式,参数的获取方法不同

    public class ConcreteSubjectA extends Observable {
        //保存数据
        private String name;
    
        //设置参数信息
        public void setInfo(String a){
            this.name=a;
        }
    
        //触发更新
        public void sendNotify(){
            setChanged(); //必须先要设置一下标志,告知已经改了
            //通知方式一;让观察者自己按需拉取(所以传参是空)
            notifyObservers();
            //通知方式二:直接把信息全部推送
            notifyObservers(name);
        }
        
        //如果是拉取的通知方式,还要给出参数的获取方法
        public String getName() {
            return name;
        }
    }

    (2) 新建观察者类,实现Observer接口,这里通常是有主题的引用的,这样可以自己完成注册,注销,和取数据

    public class FirstObserver implements Observer {
        private Observable observable;
    
        public FirstObserver(Observable observable) {
            this.observable = observable;
            observable.addObserver(this);// 在构造的时候就可以把自己注册了,不用手动添加了,如果是改造已经存在的实体类,还是需要手动添加
        }
    
        @Override
        public void update(Observable o, Object arg) {
            if(o instanceof ConcreteSubjectA){
                String name = ((ConcreteSubjectA) o).getName(); //拉取的通知方式,arg是null. 要自己获取
                //具体更新操作…… 略……
            }
        }
    }

    测试类:

    public class Test {
        public static void main(String[] args) {
            ConcreteSubjectA ca=new ConcreteSubjectA();
            FirstObserver firstObserver = new FirstObserver(ca); //构造时候注册
            ca.setInfo("我是新名字1");
            ca.sendNotify(); //自己写的通知方法,不是父类的notify
            ca.setInfo("我是新名字2");
            ca.sendNotify();
            ca.setInfo("我是新名字3");
            ca.sendNotify();
        }
    }
    /*
    运行后输出:
    已经更新啦……我是新名字1
    已经更新啦……我是新名字2
    已经更新啦……我是新名字3
     */

    java.util.Observable存在的问题:

    1、它是一个类,而不是一个接口,限制了它的复用。 想要用它就必须继承它,那就不能再继承其它类。

    2、setChanged() 等方法是被保护的,除了继承,无法使用它。违反“多用组合,少用继承”的设计原则。



  • 相关阅读:
    【整理】close 和 shutdown 的原理
    【理解】 Error 10053和 Error 10054
    【转载】 socket recv 和 read
    【转载】socket 的 connect、listen、accept 和全连接队列、半连接队列的原理
    【原创】MySQL 生产环境备份还原
    【原创】【问题记录】系统管理员设置了系统策略,禁止此安装的最终解决办法
    【原创】rabbitmq 学习
    mvc, web mvc, spring web mvc 区别
    Spring 读取配置文件的俩种方式
    移动端web开发技巧和常见问题
  • 原文地址:https://www.cnblogs.com/pikaqiucode/p/11244913.html
Copyright © 2011-2022 走看看