Observer 模式及JAVA内置的observer示例

关于观察者模式

假设今天您设计一个图形分析算表程序,当中有一个资料物件,您可以用表格图形物件、柱状图形物件、圆饼图形物件等方式来 呈现物件,无论您是用哪种图形物件,重点是若资料物件的内容作了更改,则图形物件的内容也必须跟着修改,或许您的程式中有两个以上的图形物件来呈现资料,您在图形物件上更动资料,则另一个图形物
件也必须作出相对应的变化。

主题 资料物件
观察者 柱状图形 表格图形 圆饼图形

又假设您今天设计一个网络游戏,您在服务器上维护一个连线客户端共享的资料物件,当其中一个客户端作了操作,将对此资料物件作修改,则伺服器必须通知其它 客户端作相对应的变化(像是人物位置走动、建了一个城堡等)。

主题 资料物件
观察者 客户端一 客户端二 客户端三

在Observer模式中的主角为主题(subject)与观察者(observer),观察者订阅它感兴趣的主题,一个主题可以被多个观察者订阅,当主题的状态发生变化时,它必须通知(notify)所有订阅它的观察者,观察者检视主题的状态变化,并作出对应的动作,所以Observer 模式也称之为Publish-Subscribe模式。

Observer模式的 UML 图如下所示:

Subject类中有一个notify()方法,通常是在Subject的状态发生改变时呼叫它,notify()中会呼叫 Observer的update()方法,通常会先取得Subject的新状态,然后更新Observer的显示或行为,这个过程我们可以透过 Sequence Diagram来表达:

在Java中支持观察者模式,要成为观察者的类必须实作Observer介面,这个介面中定义了一个update()方法,这个方法会被主题物件在通知状态变化时呼叫,您必须在这个方法中实作您所想要的对应行为。

主题物件会是Observable的子类,在这边注意两个重要的方法:setChanged()与notifyObserver()。 setChanged()是用来设定主题物件的状态已经被改变,而notifyObserver()方法会通知所要订阅主题物件的观察者,调用其 update()方法。

关于Java的相关源码分析

其中Java中的内置的模式的源码如下:

Observer.java接口类

仅有一个Observer的接口类,含有一个update抽象方法.

/*
 * Copyright (c) 1994, 1998, Oracle and/or its affiliates. All rights reserved.
 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 *
 */
package java.util;

/**
 * A class can implement the <code>Observer</code> interface when it
 * wants to be informed of changes in observable objects.
 *
 * @author  Chris Warth
 * @see     java.util.Observable
 * @since   JDK1.0
 */
public interface Observer {
    /**
     * This method is called whenever the observed object is changed. An
     * application calls an <tt>Observable</tt> object's
     * <code>notifyObservers</code> method to have all the object's
     * observers notified of the change.
     *
     * @param   o     the observable object.
     * @param   arg   an argument passed to the <code>notifyObservers</code>
     *                 method.
     */
    void update(Observable o, Object arg);
}

observable.java类

具体的类内容,请看注释文档,这已经非常详细了.

/*
 * 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();
    }
}<span style="font-size:18px;">
</span>

实现观察者模式

实现观察者模式非常简单,

[1]创建被观察者类,它继承自java.util.Observable类;

[2]创建观察者类,它实现java.util.Observer接口;

[3]对于被观察者类,

添加它的观察者:

    /**
     * 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);
        }
    }

addObserver()方法把观察者对象添加到观察者对象列表中。

当被观察事件发生时,执行:

/**
     * 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);
    }

以及

    /**
     * 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;
    }

只有在setChange()被调用后,notifyObservers()才会去调用update()。setChange()方法用来设置一个内部标志位注明数据发生了变化;notifyObservers()方法会去调用观察者对象列表中所有的Observer的update()方法,通知它们数据发生了变化。

[4]对于观察者类,实现Observer接口的唯一方法update

  void update(Observable o, Object arg);

形参Object arg,对应一个由notifyObservers(Object arg);传递来的参数,当执行的是notifyObservers();时,arg为null。

示例

1.NumObserable是一个被观察者,当它的成员变量data的数值发生变化时,会通知所有的观察者。

被观察者--主题类

/**
 * 被观察者--即是主题
 * @author SuooL
 * @version 1.0.0
 * <p> <a herf="suool.net" > SuooL's Blog </a>
 */
package observer;
import java.util.Observable;
/**
 * 被观察者--主题类
 *
 */

public class numObservable extends Observable {
    private int data = 0;
    /**
     * 获取数字值
     *
     * @return 取得的data
     */
    public int getData() {
       return data;
    }
    /**
     * 设置数字值
     *
     * @param i 要设置的数字值
     */
    public void setData(int i) {
       data = i;
       setChanged();
       notifyObservers();
    }
}

观察者--订阅者

/**
 * 观察者--即是订阅者
 * @author SuooL
 * @version 1.0.0
 * <p> <a herf="suool.net" > SuooL's Blog </a>
 */
package observer;
import java.util.Observable;
import java.util.Observer;
/**
 * 继承自<code>Observer</code>接口类的观察者类
 * @see java.util.Observer
 */
public class numObserver implements Observer{

	/**
	 * Observe接口类的的唯一抽象方<code>update</code>的实现
	 * <p>只有在setChange()被调用后,notifyObservers()才会去调用update()。
	 *@param o 主题类型
	 *@param arg Object类型参数,
	 *       对应一个由<code>notifyObservers(Object arg);</code>传递来的参数,
	 *       当执行的是<code>notifyObservers();</code>时,arg为<code>null</code>。
	 *
	 */
	public void update(Observable o, Object arg) {
       numObservable myObserable=(numObservable) o;
       System.out.println("Data has changed to " +myObserable.getData());
    }
}

test.

/**
 * 测试
 * @author SuooL
 * @version 1.0.0
 * <p> <a herf="suool.net" > SuooL's Blog </a>
 */
package observer;
/**
 * 测试
 */
public class observerTest {
    public static void main(String[] args) {
    	// 创建一个主题对象
    	numObservable number = new numObservable();
    	// 为主题对象增加订阅者
    	number.addObserver(new numObserver());
    	// 修改主题对象
    	number.setData(1);
    	number.setData(2);
    	number.setData(3);
    }
}

结果如下:

2.这个实例中,还是对data进行观察,拥有两个观察者,分别观察奇数和偶数的变化,通过notifyObservers(arg)中的参数arg来识别通知信息.

NumsObservable.java

/**
 * Description:
 * 被观察者--主题类
 * <p>两个私有静态变量,分别变化
 * <p>被两个订阅者订阅,分别关注不同的兴趣点--奇数变化 OR 偶数变化
 * @author SuooL
 * @version 1.0.0
 * <p> <a herf = "http://suool.net"> SuooL's Blog </a>
 */
package observers;

import java.util.Observable;
/**
 * 主题类
 */
public class NumsObservable extends Observable {
    public final static Integer ODD = 1;
    public final static Integer EVEN = 2;
    private int data = 0;
    /**
     * 获取对象的数据
     * @return data 返回取得的数据
     */
    public int getData() {
       return data;
    }
    /**
     * 设置数据变化
     * 根据数据的变化设置相应的标志变量,通知给订阅者
     * @param i 要设置的数据
     */
    public void setData(int i) {
       data = i;
       Integer flag = EVEN;
       if ((data & 0x0001) == 1)
           flag = ODD;
       setChanged();
       // 将变化的变化的标识变量通知给订阅者
       notifyObservers(flag);
    }
}
/**
 * Description:
 * 偶数观察者类
 * <p>订阅主题的内容的偶数变化
 * @author SuooL
 * @version 1.0.0
 * <p> <a herf = "http://suool.net"> SuooL's Blog </a>
 */
package observers;

import java.util.Observable;
import java.util.Observer;

/**
 * 偶数内容订阅类
 * @author SuooL
 *
 */
public class evenObserver implements Observer	{
	/**
	 * 继承自Observer接口类,update的方法的实现
	 * @param o 主题对象
	 * @param arg notifyObservers(flag);传来的参数,即是标识变量
	 */
	public void update(Observable o, Object arg) {
		if (arg == NumsObservable.EVEN) {
		NumsObservable myObserable=(NumsObservable) o;
	    System.out.println("Data has changed to EVEN number " +myObserable.getData());
	    }
	}
}
/**
 * Description:
 * 奇数观察者类
 * <p>订阅主题的内容的奇数变化
 * @author SuooL
 * @version 1.0.0
 * <p> <a herf = "http://suool.net"> SuooL's Blog </a>
 */
package observers;

import java.util.Observable;
import java.util.Observer;

/**
 * 奇数内容订阅类
 * @author SuooL
 *
 */
public class oddObserver implements Observer{
	/**
	 * 继承自Observer接口类,update的方法的实现
	 * @param o 主题对象
	 * @param arg notifyObservers(flag);传来的参数,即是标识变量
	 */
	public void update(Observable o, Object arg) {
		if (arg == NumsObservable.ODD) {
		NumsObservable myObserable=(NumsObservable) o;
	    System.out.println("Data has changed to ODD number " +myObserable.getData());
	    }
	}
}

测试类:

/**
 * Description:
 * 被观察者--主题类
 * <p>两个私有静态变量,分别变化
 * <p>被两个订阅者订阅,分别关注不同的兴趣点--奇数变化 OR 偶数变化
 * @author SuooL
 * @version 1.0.0
 * <p> <a herf = "http://suool.net"> SuooL's Blog </a>
 */
package observers;
public class NumsTest {
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		// 创建主题对象和订阅者对象
		NumsObservable observerNum = new NumsObservable();
		oddObserver oddObserver = new oddObserver();
		evenObserver evenObserver = new evenObserver();
		// 为主题增加订阅者
		observerNum.addObserver(oddObserver);
		observerNum.addObserver(evenObserver);
		// 修改主题对象内容
		observerNum.setData(12);
		observerNum.setData(11);
		observerNum.setData(10);
	}
}

运行结果:

时间: 2024-10-03 08:13:33

Observer 模式及JAVA内置的observer示例的相关文章

设计模式 - 观察者模式(Observer Pattern) Java内置 使用方法

观察者模式(Observer Pattern) Java内置 使用方法 本文地址: http://blog.csdn.net/caroline_wendy/article/details/26601659 观察者模式(observer pattern)详解, 参见: http://blog.csdn.net/caroline_wendy/article/details/26583157 Java内置的观察者模式, 是通过继承父类, 实现观察者模式的几个主要函数: Observerable(可被观

Java 性能分析工具 , 第 2 部分:Java 内置监控工具

引言 本文为 Java 性能分析工具系列文章第二篇,第一篇:操作系统工具.在本文中将介绍如何使用 Java 内置监控工具更加深入的了解 Java 应用程序和 JVM 本身.在 JDK 中有许多内置的工具,其中包括: jcmd:打印一个 Java 进程的类,线程以及虚拟机信息.适合用在脚本中.使用 jcmd - h 来查看使用方法. jconsole:提供 JVM 活动的图形化展示,包括线程使用,类使用以及垃圾回收(GC)信息. jhat:帮助分析内存堆存储. jmap:提供 JVM 内存使用信息

不使用java内置函数,将String字符串转换为int类型

package com.test; public class AtoiTest { public static void main(String[] args) throws Exception { String s = "-011134"; System.out.println("转换前的字符串:" + s); System.out.println("atoi1转换后的字符串:" + atoi1(s)); System.out.println(

JAVA内置注解 基本注解

温故而知新,可以为师矣! 每天复习,或者学习一点小东西,也能水滴石穿! 今天复习5个JAVA内置基本注解(贴代码胜过千言万语): package com.lf.test; import java.util.ArrayList; import java.util.List; public class test1 extends Object { // [email protected] (jdk1.5更新) // Override 表示:重写 @Override public String toS

设计模式之观察者模式(java内置)

DisplayElement.java,WeatherStation.java同上 WeatherData.java import java.util.Observable; public class WeatherData extends Observable { private float temperature; private float humidity; private float pressure; public float getTemperature() { return te

JAVA内置的观察者模式样本

DisplayElement.java public interface DisplayElement { public void display(); } CurrentConditionsDisplay.java import java.util.Observer; import java.util.Observable; public class CurrentConditionsDisplay implements Observer, DisplayElement { Observabl

JAVA基础整理-22. Java内置包装类

Java Object类详解:Object类的常用方法(equals()和getClass()) Object 是 Java 类库中的一个特殊类,也是所有类的父类.当一个类被定义后,如果没有指定继承的父类,那么默认父类就是 Object 类. 在 Object 类中定义的方法,在其他类中都可以使用 equals() 方法 equals() 方法的作用与运算符类似,用于值与值的比较和值与对象的比较,而 equals() 方法用于对象与对象之间的比较 getClass() 方法 getClass()

java 内置注解图

原文地址:https://blog.51cto.com/14437184/2436558

java 内置注解

public class Demo { //重写父类方法 @Override public String toString() { return ""; } //表示不建议使用 @Deprecated public static void test001() { System.out.println("aaa"); } //消除编译器左边的警告 @SuppressWarnings("all") public static void test002