频道栏目
首页 > 程序开发 > 软件开发 > 其他 > 正文
设计模式-观察者模式
2016-08-04 09:22:51         来源:BridgeGeorge  
收藏   我要投稿

介绍

??观察者模式是一个使用率非常高的设计模式,一名优秀的开发者必须掌握。它最常用的地方就是GUI系统,订阅——发布系统,因为这个模式的一个重要作用就是解耦,将观察者和被观察者解耦,使得它们之间的依赖性更小,甚至做到毫无依赖。以GUI系统为例,应用的UI具有易变性,尤其是前期随着业务的改变或者产品的需求修改,应用界面也会经常性变化,但是业务逻辑基本变化不大,此时GUI系统需要一套机制来应对这种情况,使得UI层与具体的业务逻辑解耦,观察者此时就派上用场了。

定义

定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖它的对象都会得到通知并被自动更新。

使用场景

关联行为场景,需要注意的是,关联行为是可拆分的,不是”组合”关系; 事件多级触发场景; 跨系统的消息交换场景,如消息队列,事件总线的处理机制。

UML类图

UML

Subject:抽象主题,也就是被观察(Observable)的角色,抽象主题角色把所有观察者对象的引用保存在一个集合里,每个主题都可以有任意数量的观察者,抽象主题提供一个接口,可以增加和删除观察者对象。<喎"/kf/ware/vc/" target="_blank" class="keylink">vcD4NCjxwPjxzdHJvbmc+Q29uY3JldGVTdWJqZWN0PC9zdHJvbmc+Or7fzOW1xNb3zOKjrLjDvcfJq72r09C52Ne0zKy05sjrvt/M5bnbsuzV37bUz/OjrNTavt/M5db3zOK1xMTasr/XtMyst6LJ+rjEseTKsaOsuPjL+dPQ16Ky4bn9tcS527Ls1d+3orP2zajWqqOsvt/M5db3zOK9x8mr09a90L7fzOWxu7nbsuzV36OoQ29uY3JldGVPYnNlcnZhYmxlKb3HyauhozwvcD4NCjxzdHJvbmc+T2JzZXJ2ZXI8L3N0cm9uZz46s+nP87nbsuzV36OsuMO9x8mryse527Ls1d+1xLPpz/PA4KOsy/y2qNLlwcvSu7j2uPzQwr3Tv9qjrMq5tcPU2rXDtb3W98zitcS4/LjEzajWqsqxuPzQwtfUvLqhoyA8c3Ryb25nPkNvbmNyZXRlT2JzZXJ2ZXI8L3N0cm9uZz46vt/M5bXEuduy7NXfo6y4w73HyavKtc/Ws+nP87nbsuzV373HyavL+bao0uW1xLj80MK907/ao6zS1LHj1NrW98zitcTXtMyst6LJ+rHku6/Ksbj80MLX1MnttcTXtMysoaMNCjxoMyBpZD0="观察者模式的简单实现">观察者模式的简单实现

Android 官方的开发者网站给开发者提供了一个订阅功能,开发者只要订阅就能够及时接收官方最新发布的消息。以下就来模拟这个订阅发布系统。

观察者 Coder 程序员。

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

/**
 * 观察者
 */
public class Coder implements Observer {

    public String name;

    public Coder(String name) {
        this.name = name;
    }

    @Override
    public void update(Observable o, Object arg) {
        System.out.println(name + "收到新消息," + "Android开发者网站更新,内容:" + arg);
    }

    @Override
    public String toString() {
        return "码农:" + name;
    }
}

被观察者 Android 开发者官方网站。

import java.util.Observable;
/**
 * 被观察者
 */
public class AndroidDeveloper extends Observable {
    public void postNews(String content) {
        //标识状态或内容发生变更
        setChanged();
        notifyObservers(content);
    }
}

测试类

/**
 * 测试类
 */
public class Test {
    public static void main(String[] args) {
        //被观察者
        AndroidDeveloper androidDeveloper = new AndroidDeveloper();
        //观察者
        Coder coder1 = new Coder("coder1");
        Coder coder2 = new Coder("coder2");
        Coder coder3 = new Coder("coder3");
        //注册观察者
        androidDeveloper.addObserver(coder1);
        androidDeveloper.addObserver(coder2);
        androidDeveloper.addObserver(coder3);
        //发布消息
        androidDeveloper.postNews("Android 7.0发布了");
    }
}

程序测试执行结果。

coder3收到新消息,Android开发者网站更新,内容:Android 7.0发布了
coder2收到新消息,Android开发者网站更新,内容:Android 7.0发布了
coder1收到新消息,Android开发者网站更新,内容:Android 7.0发布了

上述例子简单实现了观察者模式的基本模型。其中用到了JDK 的内置类型 Observer 和 Observable,这两个类型位于 java.util包中,目的就是为了方便开发者实现观察者模式的应用。那么jdk中到底是如何实现的呢?其实也很简单,我们可以看看JDK源码就能知道了。

首先来看

Observer
public interface Observer {
    /**
     * This method is called whenever the observed object is changed. An
     * application calls an Observable object's
     * notifyObservers method to have all the object's
     * observers notified of the change.
     *
     * @param   o     the observable object.
     * @param   arg   an argument passed to the notifyObservers
     *                 method.
     */
    void update(Observable o, Object arg);
}

它是一个接口,而接口中只有一个方法,方法参数中有两个参数,一个是被观察者Observable 一个是 Observable调用notifyObservers方法时传递的参数。下面在到Observable类中看看。

package java.util;

public class Observable {
    private boolean changed = false;
    private Vector obs;

    /**
    *无参构造函数
    */
    public Observable() {
        obs = new Vector();
    }
    /**
    * 如果观察者与集合中已有的观察者不同,则将观察者注册到可观察对象的观察者集合中
    */
    public synchronized void addObserver(Observer o) {
        if (o == null)
            throw new NullPointerException();
        if (!obs.contains(o)) {
            obs.addElement(o);
        }
    }
    /**
    * 将观察者移除观察者集合
    */
    public synchronized void deleteObserver(Observer o) {
        obs.removeElement(o);
    }

   /**
   * 如果hasChanged()方法指示对象已经改变,则通知其所有观察者,并调用clearChanged方法来指示此对象不再改变。
   */
    public void notifyObservers() {
        notifyObservers(null);
    }

    /**
    * 通知所有观察者,回调观察者的update方法,传递被观察者对象和消息参数
    */
    public void notifyObservers(Object arg) {

        Object[] arrLocal;

        synchronized (this) {
            if (!changed)
                return;
            arrLocal = obs.toArray();
            clearChanged();
        }

        for (int i = arrLocal.length-1; i>=0; i--)
            ((Observer)arrLocal[i]).update(this, arg);
    }
    /**
    * 移除所有的观察者
    */
    public synchronized void deleteObservers() {
        obs.removeAllElements();
    }
    /**
    * 设置变更标志位 true
    */
    protected synchronized void setChanged() {
        changed = true;
    }

     /**
     * 清楚变更,设置变更标志位为false
     */
    protected synchronized void clearChanged() {
        changed = false;
    }
    /**
    * 返回 变更标识
    */
    public synchronized boolean hasChanged() {
        return changed;
    }
    /**
    * 返回观察者的数量
    **/
    public synchronized int countObservers() {
        return obs.size();
    }
}

为了便于理解,类中所有成员变量和方法加了中文注释。其实总体来说还是比较简单的。

以下几点需要注意:

其中成员变量hasChanged 作为 被观察者是否发生变更的标识,每次调用notifyObservers方法通知观察者后,hasChanged都会被置为false,主动调用setChanged()方法才能重新置为true。

观察者 Observer 采用 Vector 集合存储,这是个同步集合类,内部采用数组实现,并且不能保证集合中元素的唯一,因此再添加观察者对象时,需要判定 是否已经存在此对象,防止重复添加导致观察者多次被通知。

成员方法多采用 synchronized 关键字加锁,保证了多线程访问的同步。

注意notifyObservers方法的对Vector集合的遍历顺序,采用倒序遍历方式,因此后添加的观察者会被先通知。

总结

优点

观察者和被观察者之间是抽象耦合,应对业务变化。
增强系统灵活性,可扩展性。

缺点

需要考虑一下开发效率和运行效率的问题,程序中包含一个被观察者,多个观察者,开发和调试等内容会比较复杂,而且在Java 中消息的通知默认是顺序执行的,一个观察者卡顿,会影响整体的执行效率,在这种情况下,一般考虑采用异步的方式。

点击复制链接 与好友分享!回本站首页
上一篇:策略模式
下一篇:动态库和静态库浅析
相关文章
图文推荐
文章
推荐
点击排行

关于我们 | 联系我们 | 广告服务 | 投资合作 | 版权申明 | 在线帮助 | 网站地图 | 作品发布 | Vip技术培训 | 举报中心

版权所有: 红黑联盟--致力于做实用的IT技术学习网站