JAVA的观察者模式的作用是什么

今天就跟大家聊聊有关JAVA的观察者模式的作用是什么,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。

    当对象间存在一对多关系时,则使用观察者模式(Observer Pattern)。比如,当一个对象被修改时,则会自动通知它的依赖对象。观察者模式属于行为型模式。观察者模式是Java非常重要的一个设计模式。

观察者模式所涉及的角色有:

  ●  抽象主题(Subject)角色:抽象主题角色把所有对观察者对象的引用保存在一个聚集(比如ArrayList对象)里,每个主题都可以有任何数量的观察者。抽象主题提供一个接口,可以增加和删除观察者对象,抽象主题角色又叫做抽象被观察者(Observable)角色。

  ●  具体主题(ConcreteSubject)角色:将有关状态存入具体观察者对象;在具体主题的内部状态改变时,给所有登记过的观察者发出通知。具体主题角色又叫做具体被观察者(Concrete Observable)角色。

  ●  抽象观察者(Observer)角色:为所有的具体观察者定义一个接口,在得到主题的通知时更新自己,这个接口叫做更新接口。

  ●  具体观察者(ConcreteObserver)角色:存储与主题的状态自恰的状态。具体观察者角色实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题的状态 像协调。如果需要,具体观察者角色可以保持一个指向具体主题对象的引用。

抽象主题(subject)角色:

import java.util.ArrayList;
import java.util.List;

public abstract class Subject {

    private List<MyObserver>list = new ArrayList<>();

    public void register(MyObserver myObserver){
        if (!list.contains(myObserver)){
            list.add(myObserver);
        }
    }

    public void remove(MyObserver myObserver){
        if (list.contains(myObserver)){
            list.remove(myObserver);
        }
    }

    public void notifyObserver(){
        for (MyObserver myObserver : list) {
            myObserver.update();
        }
    }


}

抽象观察者角色:

public interface MyObserver {

    void update();
}

具体主题角色:

public class Repoter extends Subject {

    private String msg;

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
        if (change()) {
            notifyObserver();
        }
    }

    public Boolean change() {
        if (msg.equals(getMsg())) {
            return true;
        } else {
            return false;
        }
    }
}

第一个具体观察者对象:

public class PeopleDaily implements MyObserver {

    private Subject subject;

    public PeopleDaily(Subject subject) {
        this.subject = subject;
        subject.register(this);
    }

    @Override
    public void update() {
        System.out.println("人民日报发布最新报道:" + ((Repoter) subject).getMsg());
    }

    public void remove() {
        subject.remove(this);
    }
}

第二个具体观察者对象:

public class NewsFeeds implements MyObserver {

    private Subject subject;

    public NewsFeeds(Subject subject) {
        this.subject = subject;
        subject.register(this);
    }

    @Override
    public void update() {
        System.out.println("新闻联播发布最新报道:" + ((Repoter) subject).getMsg());
    }

    public void remove() {
        subject.remove(this);
    }
}

第三个具体观察者对象:

public class XinHuaNewsAgency implements MyObserver {
    private Subject subject;

    public XinHuaNewsAgency(Subject subject) {
        this.subject = subject;
        subject.register(this);
    }

    @Override
    public void update() {
        System.out.println("新华社发布最新报道:" + ((Repoter) subject).getMsg());
    }

    public void remove() {
        subject.remove(this);
    }
}

测试:

public class TestDemo {

    @Test
    public void demo(){
        Repoter repoter = new Repoter();
        NewsFeeds newsFeeds = new NewsFeeds(repoter);
        XinHuaNewsAgency xinHuaNewsAgency = new XinHuaNewsAgency(repoter);
        PeopleDaily peopleDaily = new PeopleDaily(repoter);

        repoter.setMsg("为实现中华民族伟大复兴而奋斗!!!");

    }
}

结果:

新闻联播发布最新报道:为实现中华民族伟大复兴而奋斗!!!
新华社发布最新报道:为实现中华民族伟大复兴而奋斗!!!
人民日报发布最新报道:为实现中华民族伟大复兴而奋斗!!!

Process finished with exit code 0

删除一个观察者再试:

public class TestDemo {

    @Test
    public void demo(){
        Repoter repoter = new Repoter();
        NewsFeeds newsFeeds = new NewsFeeds(repoter);
        XinHuaNewsAgency xinHuaNewsAgency = new XinHuaNewsAgency(repoter);
        PeopleDaily peopleDaily = new PeopleDaily(repoter);

        repoter.setMsg("为实现中华民族伟大复兴而奋斗!!!");
        repoter.remove(xinHuaNewsAgency);
        System.out.println("————————————————————————————————————————————————");
        repoter.setMsg("华为发布最新旗舰机Mate30系列型号手机");
    }
}

结果:

新闻联播发布最新报道:为实现中华民族伟大复兴而奋斗!!!
新华社发布最新报道:为实现中华民族伟大复兴而奋斗!!!
人民日报发布最新报道:为实现中华民族伟大复兴而奋斗!!!
————————————————————————————————————————————————
新闻联播发布最新报道:华为发布最新旗舰机Mate30系列型号手机
人民日报发布最新报道:华为发布最新旗舰机Mate30系列型号手机

Process finished with exit code 0

对于观察者模式,JDK已经为我们提供了对应的接口和类。

JDK源代码:

package java.util;

/**
 * 
 * 当一个类想要被告知可观察对象的变化时,它可以实现 Observer 接口。
 * @author  Chris Warth
 * @see     java.util.Observable
 * @since   JDK1.0
 */
public interface Observer {
    /**
     * 
     * 每当观察对象发生变化时,都会调用此方法。应用程序调用 Observable 对象的 notifyObservers 方法,以便让所有对 
     * 象的观察者收到更改通知。
     * @param   o     the observable object.
     * @param   arg   an argument passed to the <code>notifyObservers</code>
     *                 method.
     */
    void update(Observable o, Object arg);
}

Observer是一个接口,只是一个方法update用于接收通知者的通知并做出相应,具体的逻辑肯定是需要开发者自己实现的了。

被观察者,JDK的源码如下:

package java.util;

/**
 * 
 * 此类表示可观察对象,或模型 - 视图范例中的“数据”。它可以被子类化以表示应用程序想要观察的对象。 
 * 可观察对象可以有一个或多个观察者。观察者可以是实现接口 Observer 的任何对象。
 * 在可观察的实例发生更改后,调用 Observable 的 notifyObservers 方法,应用程序会通过调用 update 来通知所有观察 
 * 者的更改。 
 * 未指定通知的递送顺序。 Observable类中提供的默认实现将按照它们注册的顺序通知Observers,但是子类可能会更改此顺 
 * 序,使用不保证顺序,在单独的线程上发送通知,或者可以保证它们的子类遵循此顺序,因为它们选择。 
 * 请注意,此通知机制与线程无关,并且与类 Object 的 wait 和 notify 机制完全分开。 
 * 当新创建可观察对象时,其观察者集合为空。当且仅当 equals 方法为它们返回true时,才认为两个观察者是相同的。
 * @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<Observer> obs;

    //构造方法
    public Observable() {
        obs = new Vector<>();
    }

    /**
     * 将观察者添加到此对象的观察者集中,前提是它与集合中已有的某个观察者不同。未指定将通知发送给多个观察者的顺序。
     * @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);
        }
    }

    /**
     * 
     * 从该对象的观察者集中删除观察者。将 null 传递给此方法将不起作用。
     * @param   o   the observer to be deleted.
     */
    public synchronized void deleteObserver(Observer o) {
        obs.removeElement(o);
    }

    /**
     * 
     * 如果此对象已更改,如 hasChanged 方法所示,则通知其所有观察者,然后调用 clearChanged 方法以指示此对象不再 
     * 更改。 
     * 每个观察者都使用两个参数调用 update 方法:observable对象和 null 。换句话说,此方法等效于: 
     * 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);
    }

    /**
     * 
     * 如果此对象已更改,如 hasChanged 方法所示,则通知其所有观察者,然后调用 clearChanged 方法以指示此对象不再 
     * 更改。 
     * 每个观察者都使用两个参数调用 update 方法:observable对象和 arg 参数。
     * @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) {
        /*
         * 
         * 临时数组缓冲区,用作当前Observers状态的快照。
         */
        Object[] arrLocal;

        synchronized (this) {
            /* 
             * 我们不希望Observer在拥有自己的Monitor时进行任意代码的回调。我们从Vector中提取每个Observable并存 
             * 储Observer状态的代码需要同步,但是通知观察者不会(不应该)。这里任何潜在竞争条件的最坏结果是:
             * 1)新添加的观察者将错过正在进行的通知
             * 2)最近未注册的观察者将被错误地通知
             */
            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();
    }

    /**
     * 
     * 将此 Observable 对象标记为已更改;  hasChanged 方法现在将返回 true 。
     */
    protected synchronized void setChanged() {
        changed = true;
    }

    /**
     * 
     * 表示此对象已不再更改,或者已向其所有观察者通知其最近的更改,因此 hasChanged 方法现在将返回 false 。
     * 此方法由 notifyObservers 方法自动调用。
     * @see     java.util.Observable#notifyObservers()
     * @see     java.util.Observable#notifyObservers(java.lang.Object)
     */
    protected synchronized void clearChanged() {
        changed = false;
    }

    /**
     * 
     * 测试此对象是否已更改。
     * @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;
    }

    /**
     * 
     * 返回此 Observable 对象的观察者数。
     * @return  the number of observers of this object.
     */
    public synchronized int countObservers() {
        return obs.size();
    }
}

Java源码使用Vector,Vector相比于ArrayList来说,它是线程安全的。在添加和删除观察者时对两个方法使用了synchronized关键字,这都是在为多线程考虑。

观察者:实现观察者接口(java.util.Observer),然后调用任何Observable对象的addObserver()方法,注销观察者时,就调用deleteObserver()方法即可。

第一个观察者对象:

public class XinhuaNewsAgency implements Observer {

    //被观察者对象
    private Observable observable;

    public XinhuaNewsAgency(Observable observable) {
        this.observable = observable;
        //将观察者对象加入到观察者集合中
        observable.addObserver(this);

    }

    @Override
    public void update(Observable o, Object arg) {

        if(o instanceof Repoter){
            System.out.println("新华社发布最新报道:" + ((Repoter) o).getMsg());
        }
    }

    public void remove(){
        //删除观察者
        observable.deleteObserver(this);
    }
}

第二个观察者对象:

public class PeopleDaily implements Observer {
    
    //被观察者对象
    private Observable observable;

    public PeopleDaily(Observable observable) {
        this.observable = observable;
        //将观察者对象加入到观察者集合中
        observable.addObserver(this);
    }

    @Override
    public void update(Observable o, Object arg) {

        if (o instanceof Repoter){
            System.out.println("人民日报发布最新报道:" + ((Repoter) o).getMsg());
        }
    }

    public void remove(){
        //删除观察者
        observable.deleteObserver(this);
    }
}

第三个观察者对象:

public class NewsFeeds implements Observer {

    //被观察对象
    private Observable observable;

    public NewsFeeds(Observable observable) {
        this.observable = observable;
        //将观察者对象加入到观察者集合中
        observable.addObserver(this);
    }

    @Override
    public void update(Observable o, Object arg) {

        if (o instanceof Repoter){
            System.out.println("新闻联播发布最新报道:" + ((Repoter) o).getMsg());
        }

    }

    public void remove(){
        //删除观察者
        observable.deleteObserver(this);
    }
}

被观察者:继承java.util.Observable类,调用setChanged()方法,标记状态改变。然后调用nofityObservers()方法或者notifyobservers(Object arg) 方法。

public class Repoter extends Observable {

    private String msg;

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
        this.setChanged();
        this.notifyObservers(msg);
    }

}

测试:

public class TestDemo {

    @Test
    public void demo(){
        Repoter repoter = new Repoter();
        NewsFeeds newsFeeds = new NewsFeeds(repoter);
        PeopleDaily peopleDaily = new PeopleDaily(repoter);
        XinhuaNewsAgency xinhuaNewsAgency = new XinhuaNewsAgency(repoter);
        repoter.setMsg("为实现中华民族伟大复兴而奋斗!!!");
    }
}

结果:

新华社发布最新报道:为实现中华民族伟大复兴而奋斗!!!
人民日报发布最新报道:为实现中华民族伟大复兴而奋斗!!!
新闻联播发布最新报道:为实现中华民族伟大复兴而奋斗!!!

Process finished with exit code 0

结果发现顺序和注册的顺序并不一致。将新闻联播注销,在运行:

public class TestDemo {

    @Test
    public void demo(){
        Repoter repoter = new Repoter();
        NewsFeeds newsFeeds = new NewsFeeds(repoter);
        PeopleDaily peopleDaily = new PeopleDaily(repoter);
        XinhuaNewsAgency xinhuaNewsAgency = new XinhuaNewsAgency(repoter);

        repoter.setMsg("为实现中华民族伟大复兴而奋斗!!!");
        newsFeeds.remove();
        System.out.println("————————————————————————————————————————————————");
        repoter.setMsg("华为发布最新旗舰机Mate30系列型号手机");

    }
}

结果:

新华社发布最新报道:为实现中华民族伟大复兴而奋斗!!!
人民日报发布最新报道:为实现中华民族伟大复兴而奋斗!!!
新闻联播发布最新报道:为实现中华民族伟大复兴而奋斗!!!
————————————————————————————————————————————————
新华社发布最新报道:华为发布最新旗舰机Mate30系列型号手机
人民日报发布最新报道:华为发布最新旗舰机Mate30系列型号手机

Process finished with exit code 0

劣势:

Observable是一个类,而不是一个接口,导致Observable类的扩展性不高,不如自己实现的观察者模式灵活。
Observable将某些方法保护了起来(setChanged()和clearChanged()为protected),这意味着除非继承自Observable,否则将有关键的方法不能调用。导致无法通过组合的方式使其它类获得Observable类的功能。

看完上述内容,你们对JAVA的观察者模式的作用是什么有进一步的了解吗?如果还想了解更多知识或者相关内容,请关注行业资讯频道,感谢大家的支持。