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

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了我们什么时候应该使用Observer和Observable?相关的知识,希望对你有一定的参考价值。

一位采访者问我:

什么是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)方法?

答案

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

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

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

另一答案

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

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

另一答案

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

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

现在,要做到这一点,我们必须调用某种方法。我们不希望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()传递)。
另一答案

定义

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

例子

  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

另一答案

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

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

另一答案

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

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

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

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

另一答案

如果面试官要求在不使用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:

以上是关于我们什么时候应该使用Observer和Observable?的主要内容,如果未能解决你的问题,请参考以下文章

Java 9 中不推荐使用 Observer。我们应该使用啥来代替它?

设计模式:观察者(Observer)模式

vue系列---响应式原理实现及Observer源码解析

设计模式----观察者模式通俗实例

RxJS - 发生错误时观察到的不会完成

观察者模式(Observer)的推式与拉式