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

时间:2012-12-06 13:17:55

标签: java design-patterns observable observer-pattern observers

面试官问我:

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

我不知道这些条款,所以当我回到家并开始使用谷歌搜索ObserverObservable时,我发现了来自不同资源的一些观点:

  

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

     

2)Observable类维护Observer s的列表。

     

3)更新Observable对象时,它会调用每个update()的{​​{1}}方法来通知它,它已被更改。

我找到了这个例子:

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!"); } } Observer?什么是ObservablesetChanged()方法?

10 个答案:

答案 0 :(得分:250)

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

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

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

答案 1 :(得分:54)

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

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

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

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

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

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

<强>更新

在回复您的评论时,实际的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()传递。

答案 2 :(得分:35)

<强>定义

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

<强>实施例

  1. 让我们说,您的永久地址已更改,然后您需要通知护照管理局和泛卡权限。所以这里的护照权限和泛卡权限是观察员,你是一个主题。

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

  3. 何时使用:

    1. 当一个对象更改其状态时,所有其他依赖对象必须自动更改其状态以保持一致性

    2. 当受试者不知道其拥有的观察人数时。

    3. 当一个对象应该能够在不知道对象是谁的情况下通知其他对象时。

    4. 第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.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步

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

      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

答案 3 :(得分:10)

它们是Observer design pattern的一部分。 通常,一个或多个 obervers 会了解一个 observable 中的更改。这是“某事”发生的通知,作为程序员,你可以定义“某事”的含义。

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

答案 4 :(得分:9)

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

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

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

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

答案 5 :(得分:9)

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

MyObserver作为观察者界面

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

    // ...
}

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

}

答案 6 :(得分:5)

&#34;我试图弄清楚,为什么我们需要Observer和Observable&#34;

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

这可能有用的一个示例应用程序是数据绑定,让我们假设您有一些用于编辑某些数据的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

答案 7 :(得分:3)

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

帖子的摘录:

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

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

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

答案 8 :(得分:0)

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

答案 9 :(得分:0)

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

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