一位面试官问我:

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

我不知道这些术语,所以当我回到家,开始在谷歌上搜索关于观察者和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)方法是干什么用的?


当前回答

它们是Observer设计模式的一部分。 通常,一个或多个观察者会被通知一个可观察对象的变化。它是“某事”发生的通知,作为程序员的你可以定义“某事”的含义。

当使用此模式时,您可以将这两个实体彼此分离—观察者变得可插入。

其他回答

观察者也就是回调被注册在Observable中。

它被用来告知例如在某个时间点发生的事件。它被广泛应用于Swing、Ajax、GWT中,用于对UI事件(按钮点击、文本字段更改等)进行调度操作。

在Swing中你可以找到addXXXListener(Listener l)这样的方法,在GWT中你有(Async)回调。

由于观察者列表是动态的,观察者可以在运行时注册和注销。当使用接口时,这也是一种将可观察对象与观察者分离的好方法。

"我试图弄清楚,为什么我们需要观察者和可观察对象"

正如前面的回答所述,它们提供了订阅观察者来接收可观察对象的自动通知的方法。

数据绑定是一个很有用的例子,假设你有一些UI在编辑数据,你想让UI在数据更新时做出反应,你可以让你的数据可观察,并将你的UI组件订阅到数据

Knockout.js是一个MVVM javascript框架,它有一个很好的入门教程,要想看到更多的可观察物,我真的建议你去阅读教程。http://learn.knockoutjs.com/

我还在Visual Studio 2008的开始页找到了这篇文章(观察者模式是模型-视图-控制器(MVC)开发的基础) http://visualstudiomagazine.com/articles/2013/08/14/the-observer-pattern-in-net.aspx

它们是Observer设计模式的一部分。 通常,一个或多个观察者会被通知一个可观察对象的变化。它是“某事”发生的通知,作为程序员的你可以定义“某事”的含义。

当使用此模式时,您可以将这两个实体彼此分离—观察者变得可插入。

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

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

定义

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

例子

比方说,你的永久地址改变了,那么你需要通知护照当局和pan卡当局。所以这里护照当局和泛卡当局是观察者,而你是受试者。 在Facebook上也一样,如果你订阅了某个人,那么无论何时有新的更新发生,你都会收到通知。

何时使用:

当一个对象改变其状态时,所有其他依赖对象必须自动改变其状态以保持一致性 当对象不知道它有多少观察者时。 当一个对象应该能够通知其他对象而不知道对象是谁时。

步骤1

创建Subject类。

Subject.java

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

  public class Subject {

  private List<Observer> observers 
        = new ArrayList<Observer>();
  private int state;

  public int getState() {
    return state;
  }

 public void setState(int state) {
   this.state = state;
   notifyAllObservers();
 }

   public void attach(Observer observer){
     observers.add(observer);       
   }

  public void notifyAllObservers(){
    for (Observer observer : observers) {
     observer.update();
  }
}   

}

步骤2

创建Observer类。

Observer.java

public abstract class Observer {
   protected Subject subject;
   public abstract void update();
}

步骤3

创建具体的观察者类

BinaryObserver.java

public class BinaryObserver extends Observer{

  public BinaryObserver(Subject subject){
     this.subject = subject;
     this.subject.attach(this);
  }

  @Override
  public void update() {
     System.out.println( "Binary String: " 
     + Integer.toBinaryString( subject.getState() ) ); 
  }

}

OctalObserver.java

public class OctalObserver extends Observer{

   public OctalObserver(Subject subject){
     this.subject = subject;
    this.subject.attach(this);
 }

  @Override
  public void update() {
    System.out.println( "Octal String: " 
    + Integer.toOctalString( subject.getState() ) ); 
  }

}

HexaObserver.java

public class HexaObserver extends Observer{

  public HexaObserver(Subject subject){
    this.subject = subject;
    this.subject.attach(this);
 }

  @Override
  public void update() {
     System.out.println( "Hex String: " 
    + Integer.toHexString( subject.getState() ).toUpperCase() ); 
}

}

步骤4

使用Subject和具体的观察者对象。

ObserverPatternDemo.java

 public class ObserverPatternDemo {
    public static void main(String[] args) {
       Subject subject = new Subject();

       new HexaObserver(subject);
       new OctalObserver(subject);
       new BinaryObserver(subject);

       System.out.println("First state change: 15");    
       subject.setState(15);
       System.out.println("Second state change: 10");   
       subject.setState(10);
 }

}

步骤5

验证输出。

第一个状态变化:15

十六进制字符串:F

八进制字符串:17

二进制字符串:1111

第二状态变化:10

十六进制字符串:A

八进制字符串:12

二进制字符串:1010