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

Rav*_*avi 191 java design-patterns observers observable observer-pattern

一位采访者问我:

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

我不知道这些术语的,所以,当我回到家,开始对谷歌搜索ObserverObservable,我发现来自不同资源的一些要点:

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

2)Observable该类维护一个Observers 列表.

3)当一个Observable对象被更新时,它会调用update()每个Observers 的方法来通知它,它被改变了.

我找到了这个例子:

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!");
    }
}
Run Code Online (Sandbox Code Playgroud)

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

duf*_*ymo 254

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

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

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


jbx*_*jbx 56

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

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

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


Mub*_*rak 36

定义

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

例子

  1. 可以说,你的永久地址被更改,然后你需要通知护照管理局和泛卡权.所以这里护照管理局和泛卡权威是观察员,你是一个主题.

  2. 在Facebook上,如果您订阅了某人,那么无论何时发生新的更新,您都会收到通知.

何时使用:

  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();
  }
}   
Run Code Online (Sandbox Code Playgroud)

步骤1

创建主题类.

Subject.java

public abstract class Observer {
   protected Subject subject;
   public abstract void update();
}
Run Code Online (Sandbox Code Playgroud)

}

第2步

创建Observer类.

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() ) ); 
  }
Run Code Online (Sandbox Code Playgroud)

第3步

创建具体的观察者类

BinaryObserver.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() ) ); 
  }
Run Code Online (Sandbox Code Playgroud)

}

OctalObserver.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() ); 
}
Run Code Online (Sandbox Code Playgroud)

}

HexaObserver.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);
 }
Run Code Online (Sandbox Code Playgroud)

}

第4步

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

ObserverPatternDemo.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();
  }
}   
Run Code Online (Sandbox Code Playgroud)

}

第5步

验证输出.

第一次国家变化:15

十六进制字符串:F

八进制字符串:17

二进制字符串:1111

第二次国家变化:10

十六进制字符串:A

八进制字符串:12

二进制字符串:1010

  • 我认为“定义”是一个错字。我希望这是一个错字。 (3认同)

And*_*ndy 10

它们是Observer设计模式的一部分.通常,一个或多个obervers会了解一个观察者的变化.这是一个"事情"发生的通知,作为程序员,你可以定义"某事"的含义.

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


小智 9

Observer aka回调在Observable注册.

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

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

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


Hab*_*wad 9

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

MyObserver作为观察者界面

interface MyObserver {

    void update(MyObservable o, Object arg);
}
Run Code Online (Sandbox Code Playgroud)

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

    // ...
}
Run Code Online (Sandbox Code Playgroud)

你的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);
  }

}
Run Code Online (Sandbox Code Playgroud)


Edu*_*ada 5

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

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

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

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

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