23种设计模式-观察者模式《关二爷成名后的生活》

对于许久不用的东西,容易忘记。百度许久,也未能找到自己所要。 从今日起,有些东西就记载下来,不仅方便自己,希望能帮到他人吧!

观察者模式(有时又被称为模型-视图(View)模式、源-收听者(Listener)模式或从属者模式)是软件设计模式的一种。在此种模式中,一个目标物件管理所有相依于它的观察者物件,并且在它本身的状态改变时主动发出通知。这通常透过呼叫各观察者所提供的方法来实现。此种模式通常被用来实现事件处理系统。

定义
观察者模式(Observer)完美的将观察者和被观察的对象分离开。面向对象设计的一个原则是:系统中的每个类将重点放在某一个功能上,而不是其他方面。一个对象只做一件事情,并且将他做好。观察者模式在模块之间划定了清晰的界限,提高了应用程序的可维护性和重用性。
观察者设计模式定义了对象间的一种一对多的组合关系,以便一个对象的状态发生变化时,所有依赖于它的对象都得到通知并自动刷新。

实现方式
观察者模式有很多实现方式,从根本上说,该模式必须包含两个角色:观察者和被观察对象。观察者和被观察者之间存在“观察”的逻辑关联,当被观察者发生改变的时候,观察者就会观察到这样的变化,并且做出相应的响应。

观察者: (Observer)将自己注册到被观察对象(Subject)中,被观察对象将观察者存放在一个容器(Container)里。
被观察: 被观察对象发生了某种变化,从容器中得到所有注册过的观察者,将变化通知观察者。
撤销观察: 观察者告诉被观察者要撤销观察,被观察者从容器中将观察者去除。
观察者将自己注册到被观察者的容器中时,被观察者不应该过问观察者的具体类型,而是应该使用观察者的接口。这样的优点是:假定程序中还有别的观察者,那么只要这个观察者也是相同的接口实现即可。一个被观察者可以对应多个观察者,当被观察者发生变化的时候,他可以将消息一一通知给所有的观察者。基于接口,而不是具体的实现——这一点为程序提供了更大的灵活性。

观察
实现观察者模式的时候要注意,观察者和被观察对象之间的互动关系不能体现成类之间的直接调用,否则就将使观察者和被观察对象之间紧密的耦合起来,从根本上违反面向对象的设计的原则。无论是观察者“观察”观察对象,还是被观察者将自己的改变“通知”观察者,都不应该直接调用。

例子
关二爷出名了,三国演义使得关二爷成为了武圣,各行各业皆跪拜关二哥,可是关二爷依旧是凡人一个,始终谨记–英雄?有人需要你,你就是英雄,没人需要你,你就是毒瘤。

关二爷十分低调,却引发了粉丝们的兴趣,于是各种媒体为了获得关二爷的动态实时监控关二爷。

代码如下:
JDK 中提供了 :java.util.Observable 实现类和 java.util.Observer 接口,我们不需重写,只需要实现即可。

/*
 * Copyright (c) 1994, 1998, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */
package java.util;

/**
 * A class can implement the Observer 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 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);
}

/*
 * Copyright (c) 1994, 2012, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

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.
 * 

* An observable object can have one or more observers. An observer * may be any object that implements interface Observer. After an * observable instance changes, an application calling the * Observable's notifyObservers method * causes all of its observers to be notified of the change by a call * to their update method. *

* 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. *

* Note that this notification mechanism has nothing to do with threads * and is completely separate from the wait and notify * mechanism of class Object. *

* When an observable object is newly created, its set of observers is * empty. Two observers are considered the same if and only if the * equals 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 null 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 * hasChanged method, then notify all of its observers * and then call the clearChanged method to * indicate that this object has no longer changed. *

* Each observer has its update method called with two * arguments: this observable object and null. In other * words, this method is equivalent to: *

* notifyObservers(null)
* * @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 * hasChanged method, then notify all of its observers * and then call the clearChanged method to indicate * that this object has no longer changed. *

* Each observer has its update method called with two * arguments: this observable object and the arg 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 */ // Android-changed: Call out to hasChanged() to figure out if something changes. // Upstream code avoids calling the nonfinal hasChanged() from the synchronized block, // but that would break compatibility for apps that override that method. // if (!changed) if (!hasChanged()) 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 Observable object as having been changed; the * hasChanged method will now return true. */ 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 hasChanged method will now return false. * This method is called automatically by the * notifyObservers 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 true if and only if the setChanged * method has been called more recently than the * clearChanged method on this object; * false otherwise. * @see java.util.Observable#clearChanged() * @see java.util.Observable#setChanged() */ public synchronized boolean hasChanged() { return changed; } /** * Returns the number of observers of this Observable object. * * @return the number of observers of this object. */ public synchronized int countObservers() { return obs.size(); } }

有兴趣的朋友,可以深入研究…

关二爷的类

不管关二爷是否被关注,关二爷始终要生活,所以关二爷有两个方法:1.读春秋;2.练习春秋刀法。

package model.com.hyco.ObserverPattern;

import java.util.ArrayList;
import java.util.List;
import java.util.Observable;
import java.util.Observer;

/**
 * 关二爷,超凡脱俗的人物 
 * 继承Observable,意味着被狗仔队监控了
 */
public class GuanEr extends Observable {

    public void read() {
        System.out.println("关二爷:开始读春秋...");
        //通知所有的观察者
        super.setChanged();
        this.notifyObservers("关二爷读春秋...");
    }

    public void exercise() {
        System.out.println("关二爷:开始练习春秋刀法...");
        //通知所有的观察者
        super.setChanged();
        this.notifyObservers("关二爷开始联系春秋刀法");
    }
}

某媒体 TX、YK,获取到关二爷的消息,立马发布,获取流量。

package model.com.hyco.ObserverPattern;

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

/**
 * 某媒体 TX   当Observable 通知所有观察者后,会调用Observer 中的update()方法。研读源码可知。
 */
public class TX implements Observer {
    @Override
    public void update(Observable o, Object arg) {
        System.out.println("TX 狗仔队:观察到关二爷的消息...");
        exaggerate((String) arg);
    }

    public void exaggerate(String msg) {
        System.out.println("TX 媒体 发布关二爷的消息 -->" + msg);
    }
}

package model.com.hyco.ObserverPattern;

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

/**
 * 某媒体 YK
 */
public class YK implements Observer {
    @Override
    public void update(Observable o, Object arg) {
        System.out.println("YK 狗仔队:观察到关二爷的消息...");
        exaggerate((String) arg);
    }

    public void exaggerate(String msg) {
        System.out.println("YK 媒体 发布关二爷的消息 -->" + msg);
    }
}

测试代码:

 @Test
    public void testObserver() {
        //1.定义观察者
        Observer tx = new TX();
        Observer yk = new YK();

        //2.定义关二爷 被观察者
        GuanEr guanEr = new GuanEr();

        //2.1注册
        System.out.println("没有注册,获取不到媒体的消息");
        guanEr.read();

        System.out.println("注册");
        guanEr.addObserver(tx);
        guanEr.addObserver(yk);

        //2.2 发布消息
        guanEr.read();
        System.out.println();
        guanEr.exercise();
        System.out.println();
        //2.3注销
        System.out.println("注销");
        guanEr.deleteObserver(tx);
        guanEr.deleteObserver(yk);

        System.out.println("注销之后,获取不到媒体消息");
        guanEr.read();
    }

打印结果:

没有注册,获取不到媒体的消息
关二爷:开始读春秋...
注册
关二爷:开始读春秋...
YK 狗仔队:观察到关二爷的消息...
YK 媒体 发布关二爷的消息 -->关二爷读春秋...
TX 狗仔队:观察到关二爷的消息...
TX 媒体 发布关二爷的消息 -->关二爷读春秋...

关二爷:开始练习春秋刀法...
YK 狗仔队:观察到关二爷的消息...
YK 媒体 发布关二爷的消息 -->关二爷开始联系春秋刀法
TX 狗仔队:观察到关二爷的消息...
TX 媒体 发布关二爷的消息 -->关二爷开始联系春秋刀法

注销
注销之后,获取不到媒体消息
关二爷:开始读春秋...

总结:观察者模式有些类似无序广播,生活中有很多观察者模式。比如我的这篇博文,不管你是否关注,我还是会发布,只是你没有关注,便收不到消息,如果关注了,你会收到通知,取消关注,你又收不到消息。只需要把关注改成观察即可。或者某个应用的通知,也是观察者模式。例如某个粉丝群体,每个粉丝便是单独的观察者,而被关注的人,便是被观察者。

你可能感兴趣的:(23种设计模式,Java,设计模式)