一位面试官问我:

什么是观察者和可观察对象,什么时候应该使用它们?

我不知道这些术语,所以当我回到家,开始在谷歌上搜索关于观察者和Observable的信息时,我从不同的资源中找到了一些观点:

1) Observable是一个类,Observer是一个接口。 2) Observable类维护了一个观察者列表。 3)当一个Observable对象被更新时,它会调用它的每个观察者的update()方法来通知它被更改了。

我找到了这个例子:

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

class MessageBoard extends Observable
{
    public void changeMessage(String message) 
    {
        setChanged();
        notifyObservers(message);
    }
}

class Student implements Observer 
{
    @Override
    public void update(Observable o, Object arg) 
    {
        System.out.println("Message board changed: " + arg);
    }
}

public class MessageBoardTest 
{
    public static void main(String[] args) 
    {
        MessageBoard board = new MessageBoard();
        Student bob = new Student();
        Student joe = new Student();
        board.addObserver(bob);
        board.addObserver(joe);
        board.changeMessage("More Homework!");
    }
}

但我不明白为什么我们需要观察者和可观察对象?setChanged()和notifyObservers(message)方法是干什么用的?


当前回答

如果面试官要求在不使用观察者类和接口的情况下实现观察者设计模式,您可以使用下面的简单示例!

MyObserver作为观察者接口

interface MyObserver {

    void update(MyObservable o, Object arg);
}

MyObservable作为Observable类

class MyObservable
{
    ArrayList<MyObserver> myObserverList = new ArrayList<MyObserver>();

    boolean changeFlag = false;

    public void notifyObservers(Object o)
    {
        if (hasChanged())
        {
            for(MyObserver mo : myObserverList) {
                mo.update(this, o);
            }
            clearChanged();
        }
    }


    public void addObserver(MyObserver o) {
        myObserverList.add(o);        
    }

    public void setChanged() {
        changeFlag = true;
    }

    public boolean hasChanged() {
        return changeFlag;
    }

    protected void clearChanged() {
        changeFlag = false;
    }

    // ...
}

你的MyObserver和MyObservable的例子!

class MessageBoard extends MyObservable {
  private String message;

  public String getMessage() {
    return message;
  }

  public void changeMessage(String message) {
    this.message = message;
    setChanged();
    notifyObservers(message);
  }

  public static void main(String[] args) {
    MessageBoard board = new MessageBoard();
    Student bob = new Student();
    Student joe = new Student();
    board.addObserver(bob);
    board.addObserver(joe);
    board.changeMessage("More Homework!");
  }
}

class Student implements MyObserver {

  @Override
  public void update(MyObservable o, Object arg) {
    System.out.println("Message board changed: " + arg);
  }

}

其他回答

我在这里写了一个关于观察者模式的简短描述:http://www.devcodenote.com/2015/04/design-patterns-observer-pattern.html

文章摘录如下:

观察者模式:它本质上是在对象之间建立一对多的关系,并且在相互依赖的对象之间采用松散耦合设计。

教科书定义:观察者模式定义了对象之间的一对多依赖关系,这样当一个对象改变状态时,它的所有依赖项都会被自动通知和更新。

例如,考虑一个提要通知服务。订阅模型是理解观察者模式的最佳方法。

观察者模式用于对象之间存在一对多关系时,例如如果一个对象被修改,它的依赖对象将被自动通知。

从Java9开始,这两个接口都已弃用,这意味着您不应该再使用它们。See Observer在Java 9中已弃用。我们应该用什么来代替它呢?

然而,你仍然可能会在面试中遇到关于他们的问题……

你有一个学生和留言板的具体例子。Student通过将自己添加到观察者列表来注册,观察者希望在消息发布到MessageBoard时得到通知。当消息被添加到MessageBoard时,它将遍历其观察者列表,并通知他们发生了事件。

认为Twitter。当你说你想关注某人时,Twitter会把你添加到他们的关注者列表中。当他们发送一条新的推文时,你会在输入中看到它。在这种情况下,你的Twitter账户是观察者,你关注的人是可观察对象。

这个类比可能并不完美,因为Twitter更可能是一个Mediator。但它说明了这一点。

简单来说(因为其他答案都是参考了所有的官方设计模式,所以更多的细节可以参考它们):

如果你想让一个类被程序生态系统中的其他类监视,你说你想让这个类是可观察的。也就是说,它的状态可能会有一些变化,你想要广播给程序的其余部分。

现在,要做到这一点,我们必须调用某种方法。我们不希望Observable类与感兴趣观察它的类紧密耦合。它不关心它是谁,只要它满足一定的标准。(假设这是一个广播电台,它并不关心谁在收听,只要他们把调频收音机调到他们的频率)。为了实现这一点,我们使用一个称为观察者的接口。

因此,Observable类将有一个观察者列表(例如,实现你可能拥有的观察者接口方法的实例)。每当它想要广播一些东西时,它就会一个接一个地在所有观察者上调用这个方法。

最后要解决的问题是Observable类如何知道谁感兴趣? 因此,Observable类必须提供某种机制来允许observer注册他们的兴趣。addObserver(Observer o)等方法在内部将观察者添加到观察者列表中,这样当重要事件发生时,它就会循环遍历列表,并调用列表中每个实例的观察者接口的各自通知方法。

在面试中,他们可能没有明确地问你java.util.Observer和java.util.Observable,而是问了一般的概念。这个概念是一种设计模式,Java恰好提供了直接开箱即用的支持,以帮助您在需要时快速实现它。因此,我建议您理解概念,而不是实际的方法/类(当您需要它们时可以查阅它们)。

更新

为了响应你的注释,实际的java.util.Observable类提供了以下功能:

Maintaining a list of java.util.Observer instances. New instances interested in being notified can be added through addObserver(Observer o), and removed through deleteObserver(Observer o). Maintaining an internal state, specifying whether the object has changed since the last notification to the observers. This is useful because it separates the part where you say that the Observable has changed, from the part where you notify the changes. (E.g. Its useful if you have multiple changes happening and you only want to notify at the end of the process rather than at each small step). This is done through setChanged(). So you just call it when you changed something to the Observable and you want the rest of the Observers to eventually know about it. Notifying all observers that the specific Observable has changed state. This is done through notifyObservers(). This checks if the object has actually changed (i.e. a call to setChanged() was made) before proceeding with the notification. There are 2 versions, one with no arguments and one with an Object argument, in case you want to pass some extra information with the notification. Internally what happens is that it just iterates through the list of Observer instances and calls the update(Observable o, Object arg) method for each of them. This tells the Observer which was the Observable object that changed (you could be observing more than one), and the extra Object arg to potentially carry some extra information (passed through notifyObservers().