The Observer Pattern in Java – Java中的观察者模式

最后修改: 2018年 2月 11日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

In this tutorial, we’ll describe the Observer pattern and take a look at a few Java implementation alternatives.

在本教程中,我们将描述观察者模式,并看一下一些Java实现的替代方案。

2. What Is the Observer Pattern?

2.什么是观察者模式?

Observer is a behavioral design pattern. It specifies communication between objects: observable and observers. An observable is an object which notifies observers about the changes in its state.

观察者是一种行为设计模式。它规定了对象之间的通信。observableobservers一个observable是一个通知observers有关其状态变化的对象。

For example, a news agency can notify channels when it receives news. Receiving news is what changes the state of the news agency, and it causes the channels to be notified.

例如,一个新闻机构可以在收到新闻时通知频道。收到新闻是改变新闻机构的状态,它导致渠道被通知。

Let’s see how we can implement it ourselves.

让我们看看我们如何自己实现它。

First, we’ll define the NewsAgency class:

首先,我们将定义NewsAgency类。

public class NewsAgency {
    private String news;
    private List<Channel> channels = new ArrayList<>();

    public void addObserver(Channel channel) {
        this.channels.add(channel);
    }

    public void removeObserver(Channel channel) {
        this.channels.remove(channel);
    }

    public void setNews(String news) {
        this.news = news;
        for (Channel channel : this.channels) {
            channel.update(this.news);
        }
    }
}

NewsAgency is an observable, and when news gets updated, the state of NewsAgency changes. When the change happens, NewsAgency notifies the observers about it by calling their update() method.

NewsAgency是一个可观察对象,当news被更新时,NewsAgency的状态会发生变化。当变化发生时,NewsAgency通过调用他们的update()方法来通知观察员。

To be able to do that, the observable object needs to keep references to the observers. In our case, it’s the channels variable.

为了能够做到这一点,可观察对象需要保留对观察者的引用。在我们的例子中,它是channels变量。

Now let’s see what the observer, the Channel class, can look like. It should have the update() method, which is invoked when the state of NewsAgency changes:

现在让我们看看观察者,Channel类,可以是什么样子。它应该有update()方法,当NewsAgency的状态发生变化时,它会被调用。

public class NewsChannel implements Channel {
    private String news;

    @Override
    public void update(Object news) {
        this.setNews((String) news);
    } 

    // standard getter and setter
}

The Channel interface has only one method:

Channel接口只有一个方法。

public interface Channel {
    public void update(Object o);
}

Now if we add an instance of NewsChannel to the list of observers, and change the state of NewsAgency, the instance of NewsChannel will be updated:

现在,如果我们把NewsChannel的实例添加到观察者列表中并改变NewsAgency的状态,NewsChannel的实例将被更新。

NewsAgency observable = new NewsAgency();
NewsChannel observer = new NewsChannel();

observable.addObserver(observer);
observable.setNews("news");
assertEquals(observer.getNews(), "news");

There’s a predefined Observer interface in Java core libraries, which makes implementing the observer pattern even more simple. Let’s look at it.

在Java核心库中有一个预定义的Observer接口,这使得实现观察者模式变得更加简单。让我们来看看它。

3. Implementation With Observer

3.用Observer实施

The java.util.Observer interface defines the update() method, so there’s no need to define it ourselves, as we did in the previous section.

java.util.Observer接口定义了update()方法,所以不需要像我们在上一节那样自己定义它。

Let’s see how we can use it in our implementation:

让我们看看如何在我们的实现中使用它。

public class ONewsChannel implements Observer {

    private String news;

    @Override
    public void update(Observable o, Object news) {
        this.setNews((String) news);
    }

    // standard getter and setter
}

Here, the second argument comes from Observable, as we’ll see below.

这里,第二个参数来自Observable,,我们将在下面看到。

To define the observable, we need to extend Java’s Observable class:

为了定义可观察我们需要扩展Java的Observable类。

public class ONewsAgency extends Observable {
    private String news;

    public void setNews(String news) {
        this.news = news;
        setChanged();
        notifyObservers(news);
    }
}

Note that we don’t need to call the observer’s update() method directly. We just call setChanged() and notifyObservers(), and the Observable class will do the rest for us.

请注意,我们不需要直接调用观察者的update()方法。我们只需调用setChanged()notifyObservers(),而Observable类将为我们完成剩下的工作。

It also contains a list of observers and exposes methods to maintain that list, addObserver() and deleteObserver().

它还包含一个观察者列表,并公开了维护该列表的方法:addObserver()deleteObserver()

To test the result, we just need to add the observer to this list and set the news:

为了测试结果,我们只需要将观察者添加到这个列表中并设置新闻。

ONewsAgency observable = new ONewsAgency();
ONewsChannel observer = new ONewsChannel();

observable.addObserver(observer);
observable.setNews("news");
assertEquals(observer.getNews(), "news");

The Observer interface isn’t perfect, and has been deprecated since Java 9. One of the cons is that Observable isn’t an interface, it’s a class, and that’s why subclasses can’t be used as observables.

Observer接口并不完美,从Java 9开始就被废弃了。 其中一个缺点是,Observable不是一个接口,它是一个类,这就是为什么子类不能作为观察者使用。

Also, a developer could override some of Observable‘s synchronized methods and disrupt their thread-safety.

另外,开发者可以覆盖Observable的一些同步方法,并破坏其线程安全。

Now let’s look at the ProperyChangeListener interface, which is recommended over Observer.

现在让我们看看ProperyChangeListener接口,它被推荐在Observer之上。

4. Implementation With PropertyChangeListener

4.用PropertyChangeListener实现

In this implementation, an observable must keep a reference to the PropertyChangeSupport instance. It helps to send the notifications to observers when a property of the class is changed.

在这个实现中,观察者必须保持对PropertyChangeSupport实例的引用。它有助于在类的某个属性被改变时向观察者发送通知。

Let’s define the observable:

让我们来定义一下可观察的东西。

public class PCLNewsAgency {
    private String news;

    private PropertyChangeSupport support;

    public PCLNewsAgency() {
        support = new PropertyChangeSupport(this);
    }

    public void addPropertyChangeListener(PropertyChangeListener pcl) {
        support.addPropertyChangeListener(pcl);
    }

    public void removePropertyChangeListener(PropertyChangeListener pcl) {
        support.removePropertyChangeListener(pcl);
    }

    public void setNews(String value) {
        support.firePropertyChange("news", this.news, value);
        this.news = value;
    }
}

Using this support, we can add and remove observers, and notify them when the state of the observable changes:

使用这个支持,我们可以添加和删除观察者,并在观察者的状态改变时通知他们。

support.firePropertyChange("news", this.news, value);

Here, the first argument is the name of the observed property. The second and the third arguments are its old and new value, accordingly.

这里,第一个参数是被观察到的属性的名称。第二个和第三个参数是它的旧值和新值,相应地。

Observers should implement PropertyChangeListener:

观察者应该实现 PropertyChangeListener

public class PCLNewsChannel implements PropertyChangeListener {

    private String news;

    public void propertyChange(PropertyChangeEvent evt) {
        this.setNews((String) evt.getNewValue());
    }

    // standard getter and setter
}

Due to the PropertyChangeSupport class, which is doing the wiring for us, we can restore the new property value from the event.

由于PropertyChangeSupport类为我们进行了布线,我们可以从事件中恢复新的属性值。

Let’s test the implementation to make sure that it also works:

让我们测试一下实现,确保它也能工作。

PCLNewsAgency observable = new PCLNewsAgency();
PCLNewsChannel observer = new PCLNewsChannel();

observable.addPropertyChangeListener(observer);
observable.setNews("news");

assertEquals(observer.getNews(), "news");

5. Conclusion

5.结论

In this article, we examined two ways to implement the Observer design pattern in Java. We learned that the PropertyChangeListener approach is preferred.

在这篇文章中,我们研究了在Java中实现Observer设计模式的两种方法。我们了解到,PropertyChangeListener方法是首选。

The source code for this article is available over on GitHub.

本文的源代码可在GitHub上获得。。