千家信息网

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

发表于:2025-01-22 作者:千家信息网编辑
千家信息网最后更新 2025年01月22日,今天就跟大家聊聊有关JAVA的观察者模式的作用是什么,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。当对象间存在一对多关系时,则使用观察者模式(
千家信息网最后更新 2025年01月22日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 Listlist = 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 notifyObservers     *                 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 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  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;    }    /**     *      * 返回此 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的观察者模式的作用是什么有进一步的了解吗?如果还想了解更多知识或者相关内容,请关注行业资讯频道,感谢大家的支持。

0