• Java 设计模式系列(十五)观察者模式(Observer)


    Java 设计模式系列(十五)观察者模式(Observer)

    Java 设计模式系列目录(https://www.cnblogs.com/binarylei/p/10198698.html)

    1. Java 设计模式系列(十五)观察者模式(Observer)
    2. Java 设计模式系列(十五)Spring 中的监听器模式

    观察者模式是对象的行为模式,又叫发布-订阅(Publish/Subscribe)模式、模型-视图(Model/View)模式、源-监听器(Source/Listener)模式或从属者(Dependents)模式。

    观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态上发生变化时,会通知所有观察者对象,使它们能够自动更新自己。

    一、观察者模式的结构

    图16-1 观察者模式的结构

    • Subject:目标对象,通常具有如下功能:

      1. 一个目标可以被多个观察者观察

      2. 目标提供对观察者注册和退订的维护

      3. 当目标的状态发生变化时,目标负责通知所有注册的、有效的观察者

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

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

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

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

    源代码

    (1) Subject

    /**
     * 目标对象,它知道观察它的观察者,并提供注册和删除观察者的接口
     */
    public class Subject {
        /** 用来保存注册的观察者对象 */
        private List<Observer> observers = new ArrayList<Observer>();
        /** 注册观察者对象 */
        public void attach(Observer observer) {
            observers.add(observer);
        }
        /** 删除观察者对象 */
        public void detach(Observer observer) {
            observers.remove(observer);
        }
        /** 通知所有注册的观察者对象 */
        protected void notifyObservers() {
            for(Observer observer : observers){
                observer.update(this);
            }
        }
    }
    

    (2) ConcreteSubject

    /**
     * 具体的目标对象,负责把有关状态存入到相应的观察者对象,
     * 并在自己状态发生改变时,通知各个观察者
     */
    public class ConcreteSubject extends Subject {
        /** 示意,目标对象的状态 */
        private String subjectState;
        public String getSubjectState() {
            return subjectState;
        }
        public void setSubjectState(String subjectState) {
            this.subjectState = subjectState;
            //状态发生了改变,通知各个观察者
            this.notifyObservers();
        }
    }
    

    (3) Observer

    /**
     * 观察者接口,定义一个更新的接口给那些在目标发生改变的时候被通知的对象
     */
    public interface Observer {
        /** 通知观察者 */
        public void update(Subject subject);
    
    }
    

    (4) ConcreteObserver

    /**
     * 具体观察者对象,实现更新的方法,使自身的状态和目标的状态保持一致
     */
    public class ConcreteObserver implements Observer {
        /** 示意,观者者的状态 */
        private String observerState;
        
        public void update(Subject subject) {
            // 具体的更新实现
            //这里可能需要更新观察者的状态,使其与目标的状态保持一致
            observerState = ((ConcreteSubject)subject).getSubjectState();
        }
    }
    

    二、Java 提供的观察者模式

    2.1 Java 中的观察者模式

    图16-2 Java提供的观察者模式

    其中 Observer 和 Observable 是 java.util 下的包。

    (1) ConcreteSubject

    public class ConcreteSubject extends Observable {
        /** 示意,目标对象的状态 */
        private String subjectState;
    
        public String getSubjectState() {
            return subjectState;
        }
    
        public void setSubjectState(String subjectState) {
            this.subjectState = subjectState;
    
            // 状态发生了改变,通知各个观察者
            this.setChanged();
            this.notifyObservers(subjectState);
        }
    }
    

    (2) ConcreteObserver

    public class ConcreteObserver implements Observer {
        /** 示意,观者者的状态 */
        private String observerState;
    
        @Override
        public void update(Observable o, Object obj) {
            //这是采用推的方式
            System.out.println("目标推过来的内容是:" + obj);
            //这是获取拉的数据
            System.out.println("主动到目标对象去拉的内容是:" + ((ConcreteSubject)o).getSubjectState());
        }
    }
    

    2.2 Java 中的监听者模式

    在 java.util 中有两个与事件监有关的类

    • EventObject 事件源,对事件源进行了简单的封装
    • EventListener 事件监听者,标记接口

    三、总结

    (1) 推模型和拉模型

    在观察者模式中,又分为推模型和拉模型两种方式。

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

    • 拉模型:主题对象在通知观察者的时候,只传递少量信息。如果观察者需要更具体的信息,由观察者主动到主题对象中获取,相当于是观察者从主题对象中拉数据。一般这种模型的实现中,会把主题对象自身通过 update() 方法传递给观察者,这样在观察者需要获取数据的时候,就可以通过这个引用来获取了。


    每天用心记录一点点。内容也许不重要,但习惯很重要!

  • 相关阅读:
    代码—五天前是星期几
    随手笔记-日期
    建造曲线记忆表格
    2017-5-10随手记
    java-web——第一课 tomcat
    复习
    Leetcode 24. Swap Nodes in Pairs(详细图解一看就会)
    这可能是最详细的解析HTTP走私攻击的文章
    使用grub2引导进入Linux或Window系统
    ACM集训第一次积分赛赛前复习+day4
  • 原文地址:https://www.cnblogs.com/binarylei/p/9021352.html
Copyright © 2020-2023  润新知