• java设计模式--观察者模式(Observer)


    java设计模式--观察者模式(Observer)


    观察者模式的定义:
    定义对象间的一种一对多的依赖关系。当一个对象的状态发生改变时,所有依赖于它的对象
    都得到通知并被自动更新。

    认识观察者模式:
    1.目标和观察者之间的关系:
    按照模式的定义,目标和观察者之间是典型的一对多的关系。
    但是要注意,如果观察者只有一个,也是可以的,这样就变相的实现了目标和观察者之间
    一对一的关系。

     

    2.观察者模式中有四种对象:
    Subject(目标对象),
    Observer(定义观察者接口),
    ConcreteSubject(具体的目标实现对象),
    ConcreteObserver(观察者的具体实现对象)

    一个目标可以有任意多个观察者对象,一旦目标的状态发生了改变,所有注册的观察者都会等到通知,
    然后各个观察者会对通知作出相应的响应,执行相应的业务功能处理,并使自己的状态和目标的状态保存一致。


    Subject:目标对象接口,提供如下功能:
    a.一个目标可以被多个观察者观察
    b.目标提供对观察者注册和退订的维护
    c.当目标的状态发生变化时,目标负责通知所有注册的,有效的观察者

    Observer:观察者的接口,提供目标通知时对应的更新方法,这个方法进行相应的业务处理,可以在这个方法
    里面回调目标对象,以获取目标对象的数据。

    ConcreteSubject:具体的目标实现对象,用来维护目标状态,当目标对象的状态发生改变时,通知
    所有注册的、有效的观察者,让观察者执行相应的处理。

    ConcreteObserver:观察者的具体实现对象,用来接收目标的通知,并进行相应的后续处理,比如更新
    自身的状态以保持和目标的相应状态一致。

     


    举例:

    复制代码
    import java.util.ArrayList;
    import java.util.List;
    
    /**
     * 功能:
     *         目标对象,作为被观察者,它知道观察它的观察者,并提供注册和删除观察者的接口
     * @author Administrator
     *
     */
    public class Subject
    {
        //用来保存注册的观察者对象,也就是报纸的订阅者
        private List<Observer> readers = new ArrayList<Observer>();
        
        /**
         * 功能:
         *         注册观察者对象(报纸的读者需要向报社订阅,先要注册)
         * @param observer 观察者对象
         */
        public void attach(Observer reader)
        {
            readers.add(reader);
        }
        
        /**
         * 功能:
         *         删除观察者对象(报纸的读者可以取消订阅)
         * @param observer
         */
        public void detach(Observer reader)
        {
            readers.remove(reader);
        }
        
        /**
         * 功能:
         *         通知所有的观察者
         *         (当有报纸出版后,就要主动的送到读者手中,相当于通知读者)
         */
        protected void notifyAllObservers()
        {
            for(Observer reader : readers)
            {
                reader.update(this);
            }
        }
    }
    复制代码

     

    复制代码
    /**
     * 功能:
     *         具体的目标对象,负责把有关状态存入到相应的观察者对象
     *         并在自己状态发生改变时,通知各个观察者
     *         (报纸对象)
     * @author Administrator
     *
     */
    public class NewPaper extends Subject
    {
        //报纸的具体内容
        private String content;
    
        /**
         * 功能:
         *         获取报纸的具体内容
         * @return
         */
        public String getContent()
        {
            return content;
        }
    
        /**
         * 功能:
         *         设置报纸的具体内容,相当于出版报纸
         * @param content
         */
        public void setContent(String content)
        {
            this.content = content;
            
            //通知所有注册的读者
            this.notifyAllObservers();
        }
    }
    复制代码

     

    复制代码
    /**
     * 功能:
     *         观察者接口,定义一个更新的接口给那些在目标发生改变的时候被通知的对象
     *         (报纸的读者)
     * @author Administrator
     *
     */
    public interface Observer
    {
        /**
         * 功能:
         *         更新的接口
         * @param subject 传入目标对象,方便获取相应的目标对象的状态
         */
        public void update(Subject subject);
    }
    复制代码

     

    复制代码
    /**
     * 功能:
     *         具体的观察者对象,实现更新的方法,使自身的状态和目标的状态保存一致
     *         (真正的读者)
     * @author Administrator
     *
     */
    public class Reader implements Observer
    {
        //读者的姓名
        private String name;
        
        @Override
        public void update(Subject subject)
        {
            //这里采用拉的方式
            System.out.println(name + "收到报纸,内容为: "+ ((NewPaper)subject).getContent());
        }
    
        public String getName()
        {
            return name;
        }
    
        public void setName(String name)
        {
            this.name = name;
        }
    }
    复制代码

     

    复制代码
    public class Client
    {
        public static void main(String[] args)
        {
            //创建一个报纸,作为被观察者
            NewPaper subject = new NewPaper();
            
            //创建阅读者,也就是观察者
            Reader reader1 = new Reader();
            reader1.setName("罗纳尔多");
            
            Reader reader2 = new Reader();
            reader2.setName("贝克汉姆");
            
            //注册观察者
            subject.attach(reader1);
            subject.attach(reader2);
            
            subject.setContent("世界杯要开始了哦.....");
        }
    }
    复制代码

     

     

    对上面的模式进行讲解:
    一、目标和观察者之间的关系
    按照模式的定义,目标和观察者之间是典型的一对多的关系。
    但是,观察者也可以只有一个,这样就实现了目标和观察者之间一对一的关系。

    同样,一个观察者可以观察多个目标。

     


    观察者模式中的: 推模型和拉模型

    推模型:
    目标对象主动向观察者推送目标的详细信息,不管观察者是否需要,推送的信息通常是
    目标对象的全部或部分数据

    拉模型:
    目标对象在通知观察者的时候,只传递少量信息。如果观察者需要更具体的信息,
    由观察者主动到目标对象中获取,相当于观察者从目标对象中拉数据。

     

    将上面的代码通过推模型进行实现:

    复制代码
    import java.util.ArrayList;
    import java.util.List;
    
    
    /**
     * 功能:
     *         目标对象,作为被观察者,使用推模型
     * @author Administrator
     *
     */
    public class Subject
    {    
        //用来保存注册的观察者对象(报纸订阅者)
        private List<Observer> readers = new ArrayList<Observer>();
        
        /**
         * 功能:
         *         注册观察者对象(报纸的读者需要向报社订阅,先要注册)
         * @param observer 观察者对象
         */
        public void attach(Observer reader)
        {
            readers.add(reader);
        }
        
        /**
         * 功能:
         *         删除观察者对象(报纸的读者可以取消订阅)
         * @param observer
         */
        public void detach(Observer reader)
        {
            readers.remove(reader);
        }
        
        /**
         * 功能:
         *         通知所有的观察者
         *         (当有报纸出版后,就要主动的送到读者手中,相当于通知读者)
         */
        protected void notifyAllObservers(String content)
        {
            for(Observer reader : readers)
            {
                reader.update(content);
            }
        }
    }
    复制代码

     

    复制代码
    public class NewsPaper extends Subject
    {
        private String content;
    
        public String getContent()
        {
            return content;
        }
    
        public void setContent(String content)
        {
            this.content = content;
            //通知所有注册的观察者(读者)
            this.notifyAllObservers(content);
        }
    }
    复制代码

     

    复制代码
    /**
     * 功能:
     *         观察者(报纸的读者)
     * @author Administrator
     *
     */
    public interface Observer
    {
        /**
         * 功能:
         *         被通知的方法,直接把报纸的内容推送过来
         * @param content
         */
        public void update(String content);
    }
    复制代码

     

    复制代码
    public class Reader implements Observer
    {
        //读者的姓名
        private String name;
        
        @Override
        public void update(String content)
        {
            //这里采用推的方式
            System.out.println(name + "收到报纸了,内容是:" + content);
        }
    
        public String getName()
        {
            return name;
        }
    
        public void setName(String name)
        {
            this.name = name;
        }
    }
    复制代码

     

    复制代码
    public class Client
    {
        public static void main(String[] args)
        {
            //创建一个报纸,作为被观察者
            NewsPaper subject = new NewsPaper();
            
            //创建阅读者,也就是观察者
            Reader reader1 = new Reader();
            reader1.setName("罗纳尔多");
            
            Reader reader2 = new Reader();
            reader2.setName("贝克汉姆");
            
            //注册观察者
            subject.attach(reader1);
            subject.attach(reader2);
            
            subject.setContent("世界杯要开始了哦.....");
        }
    }
    复制代码

     

    复制代码
    两种模型的比较:
    
    (1)推模型是假定目标对象知道观察者需要的数据;而拉模型是目标对象不知道观察者具体
    需要什么数据,没有办法的情况下,把自身传给观察者,让观察者自己去按需取值。
    (2)推模型可能会使得观察者对象难以复用,因为观察者定义的update方法是按需而定义的,
    可能无法兼顾没有考虑到的使用情况。这就意味着出现新情况的时候,就可能需要提供新的update方法,
    或者干脆重新实现观察者。
    
    
    
    java中的观察者
    
    在java.util包里面有一个类Observable,实现了大部分目标的功能。
    java.util包里面有一个类Observer,其中定义了update的方法,就是观察者的接口
    复制代码

     

     

    复制代码
    import java.util.Observable;
    
    public class NewsPaper extends Observable
    {
        //报纸的具体内容
        private String content;
    
        /**
         * 功能:
         *         获取报纸的具体内容
         * @return
         */
        public String getContent()
        {
            return content;
        }
    
        /**
         * 功能:
         *         设置报纸的具体内容,相当于出版报纸
         * @param content
         */
        public void setContent(String content)
        {
            this.content = content;
            
            //通知观察者
            this.setChanged();
            this.notifyObservers(this.content);//采用推的方法
            
        }
    }
    复制代码

     

    复制代码
    import java.util.Observable;
    import java.util.Observer;
    
    /**
     * 功能:
     *         观察者(读者)
     * @author Administrator
     *
     */
    public class Reader implements Observer
    {
        private String name;
        
        public String getName()
        {
            return name;
        }
    
        public void setName(String name)
        {
            this.name = name;
        }
    
        @Override
        public void update(Observable arg0, Object obj)
        {
            System.out.println(name + "收到报纸了,内容为:"+obj);
        }
    }
    复制代码

     

    复制代码
    public class Client
    {
        public static void main(String[] args)
        {
            //创建一个报纸,作为被观察者
            NewsPaper subject = new NewsPaper();
            
            //创建阅读者,也就是观察者
            Reader reader1 = new Reader();
            reader1.setName("罗纳尔多");
            
            Reader reader2 = new Reader();
            reader2.setName("贝克汉姆");
            
            //注册阅读者
            subject.addObserver(reader1);
            subject.addObserver(reader2);
            
            //出版报纸
            subject.setContent("世界杯要开始了咯");
        }
    }
    复制代码

     

    观察者模式的本质:触发联动

    当修改目标对象的状态的时候,就会触发相应的通知,然后会循环的调用所有注册的观察者对象
    的相应方法,其实就相当于联动调用这些观察者的方法。

    这个联动还是动态的,可以通过注册和取消注册来控制观察者,因而可以可以在程序运行期间,
    通过动态的控制观察者,来变相地实现添加和删除某些功能处理,这些功能就是观察者在update的
    时候执行的功能。

  • 相关阅读:
    Sql Server 创建表(可重复执行--范本)
    Sql Server 存储过程(可重复执行--范本)
    table设置了colspan之后出现td宽度显示不正常
    textarea 自适应高度
    获取系统文件
    牛客网前端编程:计算给定数组 arr 中所有元素的总和
    牛客网前端编程:删除数组中特定元素
    牛客网前端编程:找出元素 item 在给定数组 arr 中的位置
    element+vue:将Unix时间戳转化标准格式
    vue-router使用
  • 原文地址:https://www.cnblogs.com/baiduligang/p/4247420.html
Copyright © 2020-2023  润新知