zoukankan      html  css  js  c++  java
  • 设计模式——观察者模式

    观察者模式,用于一对多关系对象之间消息传递。

    观察者模式的实现需要以下几种角色:

    1、观察者的抽象角色,一般就是一个接口,里面只有一个update方法,由观察者自己去实现当收到消息后的处理

    2、观察者角色,实现观察者的抽象

    3、主题的抽象角色,一般是一个抽象类

      用于将观察者聚拢在一个集合里面,并提供观察者的增删方法,同时,提供通知所有观察者的方法。

    4、主题角色,继承于抽象主题角色,一般是在发生变化时,调用父类(抽象主题角色)的通知方法。

    关于推模型和拉模型:二者的区别在于通知观察者时传递参数不同,推模型传递的是观察者所需要的信息,拉模型传递的是被观察者本身,由观察者自动提取有效信息。

    Java的util包中提供了关于观察者模型的一些类,使用Java实现观察者模型很方便!

    1、观察者的抽象接口(Java提供                                                                                                                                            

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

    值得我们借鉴的就是在写接口的时候,方法前面尽可能不加修饰符!

    2、被观察者的抽象(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();
        }
    }

    值得学习或模仿的地方:

      * 变量没有直接初始化,而是放在构造函数里面初始化的

      * 对于观察者集合,使用了线程安全的Vector

      * 没必要暴露给外面的变量,采用了private保护,并且没有提供get方法

      * 在通知之前,修改标识变量的时候(clearChanged()方法调用时)增加了锁,考虑了线程安全,避免重复通知。

    3、主题/被观察者的实现                                                                                                                                                        

    /*
     * Copyright (c) 2017. Xiaomi.Co.Ltd All rights reserved
     */
    
    package com.pt.observer;
    
    import java.util.Observable;
    import java.util.Vector;
    
    /**
     * @description 主题,被观察者
     * @author panteng
     * @date 17-2-24.
     */
    public class Subject extends Observable {
        Vector<String> messages;
        public Subject(){
            super();
            //根据源码来看,初始化都是放在构造函数中的
            messages = new Vector<String>();
        }
        public void addMsg(String msg){
            messages.add(msg);
            setChanged();           //设置状态,标识已改变,需要通知观察者
            notifyObservers(msg);  //通知观察者
        }
    
        public Vector<String> getMessages(){
            return messages;
        }
        public void setMessages(Vector<String> messages){
            this.messages = messages;
        }
    }

    4、观察者的实现                                                                                                                                                                  

    /*
     * Copyright (c) 2017. Xiaomi.Co.Ltd All rights reserved
     */
    
    package com.pt.observer;
    
    import java.util.Observable;
    
    /**
     * @description
     * @author panteng
     * @date 17-2-24.
     */
    public class Watcher implements java.util.Observer {
        String name;
        public Watcher(){
        }
        public Watcher(String name){
            this.name = name;
        }
        /**
         * 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>
         */
        public void update(Observable o, Object arg){
            Subject mySubject = (Subject) o;
            System.out.println(this.name + ":共有 " + mySubject.getMessages().size() + " 条消息,最新消息:" + arg);
        }
    
        public String getName(){
            return name;
        }
        public void setName(String name){
            this.name = name;
        }
    }

    5、测试                                                                                                                                                                            

    /*
     * Copyright (c) 2017. Xiaomi.Co.Ltd All rights reserved
     */
    
    package com.pt.observer;
    
    import org.junit.Test;
    
    /**
     * @description
     * @author panteng
     * @date 17-2-24.
     */
    public class ObserverModelTest {
        @Test
        public void observerModelTest(){
            Subject subject = new Subject();
            Watcher watcher1 = new Watcher("watcher1");
            Watcher watcher2 = new Watcher("watcher2");
            Watcher watcher3 = new Watcher("watcher3");
            subject.addObserver(watcher1);
            subject.addObserver(watcher2);
            subject.addObserver(watcher3);
            subject.addMsg("第一条消息");
            subject.addMsg("第二条消息");
    
            subject.deleteObserver(watcher3);
            subject.addMsg("第三条消息");
        }
    }

    ===========================设计模式系列文章=========================

    简单工厂模式

    工厂方法模式

    抽象工厂模式

    建造者模式

    原型模式

    适配器模式

    桥接模式

    装饰模式

    代理模式

    组合模式

    门面模式

    享元模式

    责任链模式

    命令模式

    中介者模式

    备忘录模式

    观察者模式

    状态模式

    策略模式

    模板方法模式

    访问者模式

  • 相关阅读:
    unity UGUI实现类似NGUI切换Sprite的方式
    商业智能系统在税务行业的应用
    MSRDS机器人仿真软件学习资源汇总
    Emotiv脑电设备与RDS机器人仿真初步测试
    unity使用UGUI创建摇杆
    如何利用FineBI做财务分析
    Android4.2.2源码目录结构分析
    一个前端妹子的悲欢编程之路
    推荐一款优雅高效的免费在线APP原型工具
    数据分析概述和理论基础
  • 原文地址:https://www.cnblogs.com/tengpan-cn/p/6439103.html
Copyright © 2011-2022 走看看