码迷,mamicode.com
首页 > 其他好文 > 详细

设计模式09_观察者模式

时间:2016-06-14 10:21:30      阅读:281      评论:0      收藏:0      [点我收藏+]

标签:

          本文是在学习中的总结,欢迎转载但请注明出处:http://blog.csdn.net/pistolove/article/details/51661170


1、定义

          观察者模式定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新。(摘自Head First中文版51页)


2、说明

          在通常情况下,软件系统会包含各种对象,就像大海孕育着形色各异的动植物一样。在浩瀚的海洋中,各种动植物彼此依赖和约束,形成一个个生物链。某一种生物的行为状态变化可能会造成其它生物作出相应行动。同样,在软件系统中,常常要求在某个对象状态发生变化的同时,其它对象亦能做出相应改变。能达到这一点的方法有很多,为使系统易于复用,应选取低耦合度的设计方案;减少对象之间的耦合有利于系统的复用,同时开发者需要使这些低耦合度对象之间维持高度的协调一致,而观察者模式就是满足这一要求的众多解决方案中较为重要的方案之一。

          观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某主题对象。该主题对象状态变化时,会通知所有观察者对象,让其能够自动更新。它将观察者和被观察者的对象分离开,提高了应用程序的可维护性和重用性。

          观察者模式可分为推模型和拉模型两种方式。推模型: 主题对象向观察者推送主题的详细信息,不管观察者是否需要,推送的信息通常是主题对象的全部或部分数据。拉模型:主题对象在通知观察者的时候,只传递少量信息。如果观察者需要更具体的信息,由观察者主动到主题对象中获取,相当于是观察者从主题对象中拉数据。一般这种模型的实现中,会把主题对象自身通过update()方法传递给观察者,这样在观察者需要获取数据的时候,就可以通过这个引用来获取了。拉模型通常都是把主题对象当做参数传递。


3、角色

          抽象主题角色:将观察者对象的引用保存在集合中,抽象主题角色都可以有任意数量的观察者。抽象主题一般由抽象类或接口来实现,其提供了增加、删除观察者角色。

          抽象观察者角色:提供接口给具体观察者角色,以便在收到主题角色通知时能得以更新。

          具体主题角色:具体主题角色通常由子类来实现,当其内部状态改变时,会给所有“登记过”的观察者发通知。

          具体观察者角色:实现抽象观察者角色所提供的update方法,以使得自身状态与主题状态相协调。其通常由一个子类实现,如需要,具体观察者角色可保存指向具体主题角色的引用。


4、类图

技术分享


5、示例

          被观察者相关类如下所示:

/**
 * 被观察者接口
 */
public interface Watched {
    public void addObserver(Watcher o);

    public void deleteObserver(Watcher o);

    public void notifyObservers();

    public void deleteObservers();
}
package headfirst.news.observer;

import java.util.Vector;

/**
 * 具体的被观察者
 */
public class ConcreateWatched implements Watched {
    private boolean changed = false;
    private Vector<Watcher> obs;

    public ConcreateWatched() {
        obs = new Vector<>();
    }

    @Override
    public synchronized void addObserver(Watcher o) {
        if (o == null)
            throw new NullPointerException();
        if (!obs.contains(o)) {
            obs.addElement(o);
        }
    }

    @Override
    public synchronized void deleteObserver(Watcher o) {
        obs.removeElement(o);
    }

    @Override
    public void notifyObservers() {
        notifyObservers(null);
    }

    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--)
            ((Watcher) arrLocal[i]).update(this, arg);
    }

    @Override
    public synchronized void deleteObservers() {
        obs.removeAllElements();
    }

    protected synchronized void setChanged() {
        changed = true;
    }

    protected synchronized void clearChanged() {
        changed = false;
    }

    public synchronized boolean hasChanged() {
        return changed;
    }

    public synchronized int countObservers() {
        return obs.size();
    }
}
package headfirst.news.observer;

public class ConcreateBook extends ConcreateWatched {
    private String name = "";
    private double price = 0.0;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }

    // 当书的价格修改时调用该方法
    public void modifyPrice(ConcreateBook b) {
        // 调用父类的方法,改变被观察者的状态
        setChanged();

        // 通知客户该书已降价
        notifyObservers(b);
    }
}

          观察者相关类如下所示:

package headfirst.news.observer;

/**
 * 观察者接口 提供update方法
 */
public interface Watcher {
    void update(Watched o, Object arg);
}
package headfirst.news.observer;

public class BuyerEmail implements Watcher {
    private String buyerId = "";
    private String email = "";

    public String getBuyerId() {
        return buyerId;
    }

    public void setBuyerId(String buyerId) {
        this.buyerId = buyerId;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    // 该方法会被“被观察者的父类”既Observable调用
    public void update(Watched o, Object arg) {
        // 这里做具体发电子邮件的操作
        ConcreateBook b = (ConcreateBook) arg;
        System.out.println("给顾客的发电子邮件:" + b.getName() + "降价了,目前价格为:" + b.getPrice());
    }
}
package headfirst.news.observer;

public class BuyerMobileMessage implements Watcher {
    private String buyerId = "";
    private String mobileNo = "";

    public String getBuyerId() {
        return buyerId;
    }

    public void setBuyerId(String buyerId) {
        this.buyerId = buyerId;
    }

    public String getMobileNo() {
        return mobileNo;
    }

    public void setMobileNo(String mobileNo) {
        this.mobileNo = mobileNo;

    }

    public void update(Watched o, Object arg) {
        ConcreateBook b = (ConcreateBook) arg;
        System.out.println("给顾客的发手机短信:" + b.getName() + "降价了,目前价格为:" + b.getPrice());
    }

}
package headfirst.news.observer;

public class Main {

    public static void main(String[] args) {
        //具体的被观察者,比如京东商城上的图书
        //一旦我们对一些书籍关注,但书降价后京东就会以信息的形式告诉我们
        ConcreateBook concreateBook = new ConcreateBook();
        concreateBook.setName("<<Headfirst>>");
        concreateBook.setPrice(32.00);// 假设原价是45,现在降价促销

        //观察者在实际的应用中可以从数据库或文件中读取数据
        //手机短信
        BuyerMobileMessage bm = new BuyerMobileMessage();
        bm.setBuyerId("001");
        bm.setMobileNo("13810500085");

        //email
        BuyerEmail be = new BuyerEmail();
        be.setBuyerId("001");
        be.setEmail("dobodo@163.com");

        // 增加观察者,在实际应用中就是那些人对该书做了关注
        concreateBook.addObserver(bm);
        concreateBook.addObserver(be);
        //价格修改后调用
        concreateBook.modifyPrice(concreateBook);

    }
}
给顾客的发电子邮件:<<Headfirst>>降价了,目前价格为:32.0
给顾客的发手机短信:<<Headfirst>>降价了,目前价格为:32.0

6、总结

          观察者模式所使用的OO原则如下:

                   封装了变化。

                   多用组合,少用继承。

                   针对接口编程,不针对实现编程。

                   为交互设计的松耦合设计而努力。

          观察者模式定义了对象之间的一对多关系。主题(可观察者)用一个共同的接口来更新观察者。观察者和被观察者之间用松耦合方式结合,可观察者不知道观察者的细节,只知道观察者实现了观察者接口。

          jdk中有很多观察者模式,java.util.Observable就是其中一种,但是要注意其实现上带来的一些问题。其产生了哪些问题呢?我们发现Observable是一个“类”而不是一个“接口”,更为糟糕的是其甚至都没有实现一个接口。所以java.util.Observable的实现会产生很多问题,限制了它的使用和复用。我们要使用就必须继承它,如果一个类想同时具有Observable类和另一个超类的行为,则会陷入两难之中,毕竟java不支持多继承。在实际项目中使用观察者模式时,一定要注意这个问题,以免带来不必要的麻烦。

          本文只是简单介绍了观察者模式,并未对其进行深入探讨,略显粗糙。希望本文对你有所帮助。


设计模式09_观察者模式

标签:

原文地址:http://blog.csdn.net/pistolove/article/details/51661170

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!