我们什么时候应该使用Observer和Observable?

问题描述 投票:187回答:10

一位采访者问我:

什么是ObserverObservable,我们什么时候应该使用它们?

我不知道这些术语,所以当我回到家并开始使用Google搜索ObserverObservable时,我从不同的资源中找到了一些观点:

1)Observable是一个类,Observer是一个接口。

2)Observable类保留了Observers列表。

3)当更新Observable对象时,它会调用每个update()s的Observer方法来通知它,它会被更改。

我找到了这个例子:

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!");
    }
}

但我不明白为什么我们需要ObserverObservable?什么是setChanged()notifyObservers(message)方法?

java design-patterns observable observer-pattern observers
10个回答
251
投票

您有一个学生和MessageBoard的具体示例。学生通过将自己添加到希望在将新消息发布到MessageBoard时得到通知的观察者列表进行注册。将消息添加到MessageBoard时,它会迭代其Observers列表并通知它们事件发生。

想想Twitter。当您说想跟随某人时,Twitter会将您添加到他们的关注者列表中。当他们发送新推文时,您会在输入中看到它。在这种情况下,您的Twitter帐户是Observer,您关注的人是Observable。

这种类比可能并不完美,因为Twitter更有可能成为调解员。但它说明了这一点。


0
投票

从Java9开始,两个接口都被弃用,这意味着你不应再使用它们了。见Observer is deprecated in Java 9. What should we use instead of it?

但是,你可能仍会得到关于他们的面试问题......


54
投票

用非常简单的术语(因为其他答案指的是所有官方设计模式,所以请查看它们以获取更多细节):

如果您想拥有一个由程序生态系统中的其他类监视的类,则表示您希望该类是可观察的。即它的状态可能会有一些变化,你想要广播到程序的其余部分。

现在,要做到这一点,我们必须调用某种方法。我们不希望Observable类与有兴趣观察它的类紧密耦合。只要满足某些标准,它就不关心它是谁。 (想象一下,这是一个广播电台,只要他们在频率上调谐FM收音机就不关心谁在听。)为此,我们使用一个称为Observer的接口。

因此,Observable类将有一个Observers列表(即实现您可能具有的Observer接口方法的实例)。每当它想要广播某些内容时,它就会一个接一个地调用所有观察者的方法。

关闭这个难题的最后一件事是Observable类将如何知道谁感兴趣?所以Observable类必须提供一些机制来允许Obse​​rvers注册他们的兴趣。像addObserver(Observer o)这样的方法在内部将Observer添加到观察者列表中,这样当重要事件发生时,它会循环遍历列表并调用列表中每个实例的Observer接口的相应通知方法。

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

UPDATE

在回应您的评论时,实际的java.util.Observable课程提供以下设施:

  1. 维护java.util.Observer实例列表。有兴趣获得通知的新实例可以通过addObserver(Observer o)添加,并通过deleteObserver(Observer o)删除。
  2. 维护内部状态,指定自上次通知观察者后对象是否已更改。这很有用,因为它将您说Observable已更改的部分与通知更改的部分分开。 (例如,如果您发生了多次更改,并且您只想在流程结束时通知而不是在每个小步骤中通知,那么它很有用)。这是通过setChanged()完成的。因此,当你改变某些东西到Observable时,你只需要调用它,你希望其余的Observers最终知道它。
  3. 通知所有观察者特定的Observable已改变状态。这是通过notifyObservers()完成的。在继续通知之前,这将检查对象是否已实际更改(即,对setChanged()进行了调用)。有两个版本,一个没有参数,另一个带有Object参数,以防你想要通知一些额外的信息。在内部发生的事情是它只是遍历Observer实例列表并为每个实例调用update(Observable o, Object arg)方法。这告诉Observer哪个是Observable对象改变了(你可以观察多个),而额外的Object arg可能带有一些额外的信息(通过notifyObservers()传递)。

35
投票

定义

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

例子

  1. 比方说,您的永久地址已更改,然后您需要通知护照管理局和pan卡权限。所以这里的护照权限和泛卡权限是观察员,你是一个主题。
  2. 在Facebook上,如果您订阅了某人,那么无论何时发生新的更新,您都会收到通知。

何时使用:

  1. 当一个对象更改其状态时,所有其他依赖对象必须自动更改其状态以保持一致性
  2. 当受试者不知道它拥有的观察者数量时。
  3. 当一个对象应该能够在不知道对象是谁的情况下通知其他对象。

步骤1

创建主题类。

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步

创建具体的观察者类

binary observer.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() ) ); 
  }

}

octal observer.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() ) ); 
  }

}

hex啊observer.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步

使用主题和具体观察者对象。

observer pattern demo.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


10
投票

他们是Observer design pattern的一部分。通常,一个或多个obervers会了解一个可观察者的变化。这是一个“事情”发生的通知,作为程序员,你可以定义“某事”的含义。

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


9
投票

观察者a.k.a回调在Observable注册。

它用于通知例如关于某些时间发生的事件。它广泛用于Swing,Ajax,GWT,用于例如调度操作。 UI事件(按钮点击,文本字段更改等)。

在Swing中,您可以在GWT中找到类似addXXXListener(Listener l)的方法(Async)回调。

由于观察者列表是动态的,观察者可以在运行时注册和取消注册。当使用接口时,它也是将观察者与观察者分离的好方法。


9
投票

如果面试官要求在不使用Observer类和接口的情况下实现Observer design pattern,则可以使用以下简单示例!

MyObserver as observer interface

interface MyObserver {

    void update(MyObservable o, Object arg);
}

MyObservable as Observable class

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;
    }

    // ...
}

Your example with MyObserver and 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);
  }

}

5
投票

“我试图弄明白,为什么我们需要Observer和Observable”

如前所述,它们提供了订阅观察者以接收可观察者的自动通知的方法。

这可能有用的一个示例应用程序是数据绑定,假设您有一些用于编辑某些数据的UI,并且您希望UI在数据更新时做出反应,您可以使您的数据可观察,并订阅您的UI组件数据

Knockout.js是一个MVVM javascript框架,它有一个很棒的入门教程,可以看到更多可观察的动作我真的建议通过本教程。 http://learn.knockoutjs.com/

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


3
投票

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

帖子的片段:

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

TextBook定义:Observer模式定义了对象之间的一对多依赖关系,这样当一个对象更改状态时,其所有依赖关系都会自动得到通知和更新。

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


0
投票

当对象之间存在一对多关系时使用观察者模式,例如,如果修改了一个对象,则会自动通知其依赖对象。

© www.soinside.com 2019 - 2024. All rights reserved.