zoukankan      html  css  js  c++  java
  • 设计模式走一遍---观察者模式(下)

    上篇我们讲解了观察者模式的一些知识,而且自定义观察者模式的经典代码,(传送们:设计模式走一遍—-观察者模式(上))

    这篇简单讲一下JDK自带的观察者模式实现代码。

    对于观察者模式,JDK中提供了一个Observer接口(观察者),一个Observable类(主题对象)。

    注:被观察者又被称为主题对象,目标对象。

    具体我们来看下源码。

    1.观察者接口

    public interface Observer {
        /**
         * This method is called whenever the observed *object is changed. 
         *当被观察者发生变化时,该方法将会被调用
         * @param   o     the observable object.
         * @param   arg   an argument passed to the <code>notifyObservers</code>
         *                 method.
         */
        void update(Observable o, Object arg);
    }
    

    该接口相当于观察者,里面有一个update(Observable o, Object arg)方法,Observable参数是指主题对象,该参数指明该观察者是属于哪一个主题对象的。

    arg参数可以是任意对象,假如主题对象在发送通知时,想要传递什么数据给观察者,那么就可以把数据对象传递给arg参数。

    2.主题对象类(方法有点多,我就不放英文解释了)

    //主题对象可以是接口、抽象类、具体类,我们上节说
    //一般采用抽象类,不过JDK这里使用的是具体类
    public class Observable {
        //标记主题对象的状态是否改变
        private boolean changed = false;
        //存放观察者集合,之所以用Vector而不用ArrayList
        //主要是Vector是线程安全的
        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);
        }
    
        //标记该对象的状态是否发送了改变
        protected synchronized void setChanged() {
            changed = true;
        }
    
        //指示该对象不会再发生改变,或者它已经通知了
        //所有观察者
        protected synchronized void clearChanged() {
            changed = false;
        }
    
    
        //测试对象是否发生了改变。当且仅当在此对象最近
        //调用了setChange()方法
        public synchronized boolean hasChanged() {
            return changed;
        }
    
        //如果hasChanged()方法指示此对象发送了改变,
        //则通知所有观察者,并且调用clearChanged()方法
        //指示此对象不再改变
        public void notifyObservers() {
            notifyObservers(null);
        }
    
        //与上面没有参数的同名方法相同,只是如果这个方
        //法的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();
        }
    
        //返回观察者的数量
        public synchronized int countObservers() {
            return obs.size();
        }
    }
    

    该具体类Observable相当于主题对象,实现的主要功能就是当自己的状态发送改变时,通知观察者,观察者再根据通知,在update方法做出相应的反应。

    简单写个Demo测试下。

    public class Test {
        public static void main(String[] args){
            //创建一个主题对象
            AnimalSubject animalSubject = new AnimalSubject();
            animalSubject.addObserver(new DogObsever());
            animalSubject.addObserver(new LionObsever());
            //状态发生改变
            animalSubject.setChanged();
            //通知观察者
            animalSubject.notifyObservers();
        }
    }
    
    //动物主题,弄子类方便拓展主题对象功能
    class AnimalSubject extends Observable{
        //不过我就不新增代码、方法了
    
        //不覆盖下的话,上面的测试调用不了setChange()方法
        //为了方便测试,覆盖重写下
        @Override
        protected synchronized void setChanged() {
            super.setChanged();
        }
    }
    class DogObsever implements Observer{
        @Override
        public void update(Observable o, Object arg) {
            System.out.println("收到通知,小狗观察者正在做出相应处理");
        }
    }
    
    class LionObsever implements Observer{
        @Override
        public void update(Observable o, Object arg) {
            System.out.println("收到通知,狮子观察者正在做出相应处理");
        }
    }
    

    打印结果

    收到通知,狮子观察者正在做出相应处理
    收到通知,小狗观察者正在做出相应处理
    

    从上面的代码中我们可以发现JDk内置的观察者模式中的主题对象是一个具体类,而不是一个抽象类或接口,而且setChange()方法还被保护起来了(被定义为protected),这就意味着,要在别的类中调用该方法,那么我们必须继承在子类中重写覆盖该方法。显然,我觉得这很不友好…..

    可能这也是JDK内置的观察者模式很少被拿来使用 的原因吧,一般都是自己来自定义观察者模式。

    希望大家能够动手写一下这些代码,可能会碰到一些你没想到的问题。

    关注公我的众号:苦逼的码农,获取更多原创文章,后台回复礼包送你一份时下热门的资源大礼包。同时也感谢把文章介绍给更多需要的人

  • 相关阅读:
    CentOS 8.0配置阿里云yum源和epel源
    CentOS8 安装epel 使用阿里云镜像
    centos下yum使用proxy代理方法
    MySQL中的事务控制(一)start transaction
    MySQL中的锁定语句: lock tables 和 unlock tables
    MySQL中的触发器
    MySQL中的事件调度器
    MySQL中的流程控制
    MySQL中的不可见索引、倒序索引
    IDEA出现Push to origin/master was rejected
  • 原文地址:https://www.cnblogs.com/kubidemanong/p/9597357.html
Copyright © 2011-2022 走看看