zoukankan      html  css  js  c++  java
  • Java设计模式之行为型模式(观察者模式)

    观察者模式(Observer)

    1、背景

    在软件开发中,当一个类发生变化,需要通知其他类,并让其他类做某些逻辑操作,观察者模式应运而生。

    2、概述

    ①定义

    将主类与其他多个类建立一种“一对多”的通信关系,当“主类“发生某些操作时,与之建立从属关系的类作出反应。

    ②应用场景

    • 监听某个类的运行情况
    • 被监听类分发信息、监听类订阅信息场景
    • 多个程序的同步更新
    • 同步产生程序运行日志

    ③优势

    • 一次修改处处运行,提高程序运行时的扩展性
    • 能够监听被监听对象的运行状态,有利于后期维护
    • 有利于完善代码的相关功能,如:消息订阅发布。

    ④结构

    附图:

    这里写图片描述

    • Observable为抽象类,是所有被监听类的父类。observers属性用于存储观察类;addObserver、removeObserver为observers这一属性的相关操作;modify为Observable抽象类的改变方法

    • Observer为观察者接口,update为接口方法。

    • Target类为Observable的子类

    • Observer1、Observer2为Observer接口的实现类。实现了update方法

    3、实例分析

    观察者模式分为以下几种:

    • 缺省模式
    • 推模式
    • 拉模式
    • 复合模式

    ①缺省模式

    附图:

    这里写图片描述

    缺省模式与上面讲的观察者模式结构图一致。拥有Observable、Observer、Target、Observer1、Observer2这些单位。观察者模式中的缺省模式只注重观察者的方法调用,并不注重观察者对被观察者的数据交互。事实上:只调用方法,不涉及数据侵入。

    下面是实例代码:

    import java.util.Vector;
    
    /**
     * @author Hanlin Wang
     */
    
    public class ObserverMode {
        public static void main(String[] args) {
            //创建两种类型的观察者
            Observer1 ob1 = new Observer1();
            Observer2 ob2 = new Observer2();
            //交付给Target管理
            Target.addObserver(ob1);
            Target.addObserver(ob2);
            //Target发生改变,观察者发出响应。
            Target.modify();
        }
    }
    
    //添加可观察抽象类
    abstract class Observable{
        private static Vector<Observer> observers = new Vector<Observer>();
        public static void addObserver(Observer ob){
            observers.add(ob);
        }
        public static void removeObserver(Observer ob){
            observers.remove(ob);
        }
        public static void notifyObservers(){
            for (Observer observer : observers) {
                observer.update();
            }
        }
        public static void modify(){
            System.out.println("Observable has been modified");
            notifyObservers();
        }
    }
    
    //被观察实际类
    class Target extends Observable{
    
    }
    
    //观察者接口
    interface Observer{
        void update();
    }
    
    //添加观察者1、2
    class Observer1 implements Observer{
        public void update(){
            System.out.println("Observer1 has been awakened");
        }
    }
    
    class Observer2 implements Observer{
        public void update(){
            System.out.println("Observer2 has been awakened");
        }
    }

    打印结果:

    Observable has been modified
    Observer1 has been awakened
    Observer2 has been awakened

    分析:创建两个Observer类对象:ob1、ob2。利用Target的静态方法addObserver将ob1、ob2在Target中注册,至此,ob1、ob2就成为了Target的观察者,监听着Target中modify方法的调用。从打印结果可以知晓,当Target中的modify方法调用时,ob1、ob2的方法也相继被调用。Target只是担任了ob1、ob2的update方法的触发器,并没有改变ob1、ob2的update方法中的内部逻辑。这就是缺省状态下的观察者模式。

    ②推模式

    推模式较缺省模式,被观察者会对观察者推送额外的信息。

    附图:

    这里写图片描述

    代码:

    import java.util.Vector;
    
    /**
     * @author Hanlin Wang
     */
    
    public class ObserverMode {
        public static void main(String[] args) {
            //创建两种类型的观察者
            Observer1 ob1 = new Observer1();
            Observer2 ob2 = new Observer2();
            //交付给Target管理
            Target.addObserver(ob1);
            Target.addObserver(ob2);
            //Target发生改变,观察者发出响应。
            Target.modify();
        }
    }
    
    //添加可观察抽象类
    abstract class Observable{
        private static Vector<Observer> observers = new Vector<Observer>();
        public static void addObserver(Observer ob){
            observers.add(ob);
        }
        public static void removeObserver(Observer ob){
            observers.remove(ob);
        }
        public static void notifyObservers(){
            for (Observer observer : observers) {
                observer.update("Target向观察者发送的message");
            }
        }
        public static void modify(){
            System.out.println("Observable has been modified");
            notifyObservers();
        }
    }
    
    //被观察实际类
    class Target extends Observable{
    
    }
    
    //观察者接口
    interface Observer{
        void update(String message);
    }
    
    //添加观察者1、2
    class Observer1 implements Observer{
        public void update(String message){
            System.out.println("Observer1 : "+message);
        }
    }
    
    class Observer2 implements Observer{
        public void update(String message){
            System.out.println("Observer1 : "+message);
        }
    }

    分析:推模式较缺省模式,Observer1、Observer2中的update的方法需要传入一个String类型的参数,打印的结果将附加该参数的值,这样就体现了被观察者对观察者的信息交互推送,而不是缺省模式下的只调用方法。

    ③拉模式

    推模式虽然能推送信息,但是这种推送方式具有局限性:每次只能统一推送一定的消息,无法做到具体化,个例化推送,并且观察者无法真正对被观察者的数据进行操作。拉模式就解决了推模式推送信息单一的问题。拉模式将当前被观察对象作为update的参数,即update(Observable o),这样观察者就可以直接操纵被观察者中的相关数据。

    拉模式相较推模式需要修改的地方:Target类中定义成员变量data,用于代表被观察者类的数据信息;update方法改为update(Observable o),即观察者接受一个参数。

    附图:

    这里写图片描述

    代码:

    import java.util.Vector;
    
    /**
     * @author Hanlin Wang
     */
    
    public class ObserverMode {
        public static void main(String[] args) {
            //创建两种类型的观察者
            Observer1 ob1 = new Observer1();
            Observer2 ob2 = new Observer2();
            //交付给Target管理
            Target.addObserver(ob1);
            Target.addObserver(ob2);
            //Target发生改变,观察者发出响应。
            Target.modify();
        }
    }
    
    //添加可观察抽象类
    abstract class Observable{
        private static Vector<Observer> observers = new Vector<Observer>();
        public static void addObserver(Observer ob){
            observers.add(ob);
        }
        public static void removeObserver(Observer ob){
            observers.remove(ob);
        }
        public static void notifyObservers(){
            for (Observer observer : observers) {
                observer.update(new Target());
            }
        }
        public static void modify(){
            System.out.println("Observable has been modified");
            notifyObservers();
        }
    }
    
    //被观察实际类
    class Target extends Observable{
        private static String data = "zhangsan";
    
        public static String getData() {
            return data;
        }
    
        public static void setData(String data) {
            Target.data = data;
        }
    }
    
    //观察者接口
    interface Observer{
        void update(Observable o);
    }
    
    //添加观察者1、2
    class Observer1 implements Observer{
        public void update(Observable o){
            System.out.println(((Target)o).getData());
        }
    }
    
    class Observer2 implements Observer{
        public void update(Observable o){
            System.out.println(((Target)o).getData());
        }
    }

    private static String data = “zhangsan”为Targe类中的静态常量,修改update方法修改为update(Observable o)。

    运行结果:

    Observable has been modified
    zhangsan
    zhangsan

    4、Java对观察者模式的支持

    在java.util包下存在两个工具类:Observable、Observer。Observable为普通类,Observer为接口。Observable原生支持复合模式的观察者模式,即:被观察者既要对观察者推送信息,观察者也可以访问、操作被观察者的相关属性或方法,既有“推”,又有“拉”。

    附图:

    这里写图片描述

    代码:

    import java.util.Observable;
    import java.util.Observer;
    
    public class Q {
        public static void main(String[] args) {
            Subject subject = new Subject("iPhone 7");
            Ob1 ob1 = new Ob1();
            Ob2 ob2 = new Ob2();
            subject.addObserver(ob1);
            subject.addObserver(ob2);
            subject.change();
            //观察类对象个数
            System.out.println(subject.countObservers());
        }
    }
    
    class Subject extends Observable{
        private String data;
    
        public Subject(String data) {
            super();
            this.data = data;
        }
    
        public String getData() {
            return data;
        }
    
        public void setData(String data) {
            this.data = data;
        }
    
        public void change(){
            setChanged();
            notifyObservers("hahaha");
        }
    }
    
    class Ob1 implements Observer{
        public void update(Observable o, Object arg) {
            System.out.println("the message is : "+ arg +", the Subject's data is : "+((Subject)o).getData());
        }
    }
    
    class Ob2 implements Observer{
        public void update(Observable o, Object arg) {
            System.out.println("the message is : "+ arg +", the Subject's data is : "+((Subject)o).getData());
        }
    }

    运行结果:

    the message is : hahaha, the Subject’s data is : iPhone 7
    the message is : hahaha, the Subject’s data is : iPhone 7
    2

    如果大家对Observable类不太了解,下面附带JDK源码:

    /*
     * Copyright (c) 1994, 2004, Oracle and/or its affiliates. All rights reserved.
     * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     */
    
    package java.util;
    
    /**
     * This class represents an observable object, or "data"
     * in the model-view paradigm. It can be subclassed to represent an
     * object that the application wants to have observed.
     * <p>
     * An observable object can have one or more observers. An observer
     * may be any object that implements interface <tt>Observer</tt>. After an
     * observable instance changes, an application calling the
     * <code>Observable</code>'s <code>notifyObservers</code> method
     * causes all of its observers to be notified of the change by a call
     * to their <code>update</code> method.
     * <p>
     * The order in which notifications will be delivered is unspecified.
     * The default implementation provided in the Observable class will
     * notify Observers in the order in which they registered interest, but
     * subclasses may change this order, use no guaranteed order, deliver
     * notifications on separate threads, or may guarantee that their
     * subclass follows this order, as they choose.
     * <p>
     * Note that this notification mechanism is has nothing to do with threads
     * and is completely separate from the <tt>wait</tt> and <tt>notify</tt>
     * mechanism of class <tt>Object</tt>.
     * <p>
     * When an observable object is newly created, its set of observers is
     * empty. Two observers are considered the same if and only if the
     * <tt>equals</tt> method returns true for them.
     *
     * @author  Chris Warth
     * @see     java.util.Observable#notifyObservers()
     * @see     java.util.Observable#notifyObservers(java.lang.Object)
     * @see     java.util.Observer
     * @see     java.util.Observer#update(java.util.Observable, java.lang.Object)
     * @since   JDK1.0
     */
    public class Observable {
        private boolean changed = false;
        private Vector obs;
    
        /** Construct an Observable with zero Observers. */
    
        public Observable() {
            obs = new Vector();
        }
    
        /**
         * Adds an observer to the set of observers for this object, provided
         * that it is not the same as some observer already in the set.
         * The order in which notifications will be delivered to multiple
         * observers is not specified. See the class comment.
         *
         * @param   o   an observer to be added.
         * @throws NullPointerException   if the parameter o is null.
         */
        public synchronized void addObserver(Observer o) {
            if (o == null)
                throw new NullPointerException();
            if (!obs.contains(o)) {
                obs.addElement(o);
            }
        }
    
        /**
         * Deletes an observer from the set of observers of this object.
         * Passing <CODE>null</CODE> to this method will have no effect.
         * @param   o   the observer to be deleted.
         */
        public synchronized void deleteObserver(Observer o) {
            obs.removeElement(o);
        }
    
        /**
         * If this object has changed, as indicated by the
         * <code>hasChanged</code> method, then notify all of its observers
         * and then call the <code>clearChanged</code> method to
         * indicate that this object has no longer changed.
         * <p>
         * Each observer has its <code>update</code> method called with two
         * arguments: this observable object and <code>null</code>. In other
         * words, this method is equivalent to:
         * <blockquote><tt>
         * notifyObservers(null)</tt></blockquote>
         *
         * @see     java.util.Observable#clearChanged()
         * @see     java.util.Observable#hasChanged()
         * @see     java.util.Observer#update(java.util.Observable, java.lang.Object)
         */
        public void notifyObservers() {
            notifyObservers(null);
        }
    
        /**
         * If this object has changed, as indicated by the
         * <code>hasChanged</code> method, then notify all of its observers
         * and then call the <code>clearChanged</code> method to indicate
         * that this object has no longer changed.
         * <p>
         * Each observer has its <code>update</code> method called with two
         * arguments: this observable object and the <code>arg</code> argument.
         *
         * @param   arg   any object.
         * @see     java.util.Observable#clearChanged()
         * @see     java.util.Observable#hasChanged()
         * @see     java.util.Observer#update(java.util.Observable, java.lang.Object)
         */
        public void notifyObservers(Object arg) {
            /*
             * a temporary array buffer, used as a snapshot of the state of
             * current Observers.
             */
            Object[] arrLocal;
    
            synchronized (this) {
                /* We don't want the Observer doing callbacks into
                 * arbitrary code while holding its own Monitor.
                 * The code where we extract each Observable from
                 * the Vector and store the state of the Observer
                 * needs synchronization, but notifying observers
                 * does not (should not).  The worst result of any
                 * potential race-condition here is that:
                 * 1) a newly-added Observer will miss a
                 *   notification in progress
                 * 2) a recently unregistered Observer will be
                 *   wrongly notified when it doesn't care
                 */
                if (!changed)
                    return;
                arrLocal = obs.toArray();
                clearChanged();
            }
    
            for (int i = arrLocal.length-1; i>=0; i--)
                ((Observer)arrLocal[i]).update(this, arg);
        }
    
        /**
         * Clears the observer list so that this object no longer has any observers.
         */
        public synchronized void deleteObservers() {
            obs.removeAllElements();
        }
    
        /**
         * Marks this <tt>Observable</tt> object as having been changed; the
         * <tt>hasChanged</tt> method will now return <tt>true</tt>.
         */
        protected synchronized void setChanged() {
            changed = true;
        }
    
        /**
         * Indicates that this object has no longer changed, or that it has
         * already notified all of its observers of its most recent change,
         * so that the <tt>hasChanged</tt> method will now return <tt>false</tt>.
         * This method is called automatically by the
         * <code>notifyObservers</code> methods.
         *
         * @see     java.util.Observable#notifyObservers()
         * @see     java.util.Observable#notifyObservers(java.lang.Object)
         */
        protected synchronized void clearChanged() {
            changed = false;
        }
    
        /**
         * Tests if this object has changed.
         *
         * @return  <code>true</code> if and only if the <code>setChanged</code>
         *          method has been called more recently than the
         *          <code>clearChanged</code> method on this object;
         *          <code>false</code> otherwise.
         * @see     java.util.Observable#clearChanged()
         * @see     java.util.Observable#setChanged()
         */
        public synchronized boolean hasChanged() {
            return changed;
        }
    
        /**
         * Returns the number of observers of this <tt>Observable</tt> object.
         *
         * @return  the number of observers of this object.
         */
        public synchronized int countObservers() {
            return obs.size();
        }
    }

    代码量的确很多,大家只需要关注setChanged和notifyObservers这个方法,在使用时需要定义一个Subject类继承Observable类,你可以自己定义一个方法(如我自己定义的change()方法),该方法中执行逻辑必须要有setChanged()方法调用和notifyObservers()方法调用,且setChanged必须在notifyObservers方法之前调用。具体实现的逻辑可以参考notifyObservers(null)和notifyObservers(Object arg)。

  • 相关阅读:
    ZYAR20A 亚克力2驱 蓝牙 298寻迹避障机器人 —— 小车按键启动和蜂鸣器报警
    ZYAR20A 亚克力2驱 蓝牙 298寻迹避障机器人 —— 小车指定花式动作
    ZYAR20A 亚克力2驱 蓝牙 298寻迹避障机器人 —— 小车指定花式动作
    ZYAR20A 亚克力2驱 蓝牙 298寻迹避障机器人 —— 小车指定花式动作
    ZYAR20A 亚克力2驱 蓝牙 298寻迹避障机器人 —— 小车前后左右综合实验
    ZYAR20A 亚克力2驱 蓝牙 298寻迹避障机器人 —— 小车前后左右综合实验
    ZYAR20A 亚克力2驱 蓝牙 298寻迹避障机器人 —— 小车前后左右综合实验
    asp中设置session过期时间方法总结
    asp中设置session过期时间方法总结
    ASP.NET关于Session_End触发与否的问题
  • 原文地址:https://www.cnblogs.com/wanxi/p/6476230.html
Copyright © 2011-2022 走看看