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

一位面试官问我:

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

我不知道这些术语,所以当我回到家,开始在谷歌上搜索ObserverObservable时,我从不同的资源中找到了一些点:

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

2) Observable类维护一个__abc1的列表。

3)当一个Observable对象被更新时,它会调用它的每个__abc2的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!");
}
}

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

173180 次浏览

你有一个学生和留言板的具体例子。Student通过将自己添加到观察者列表来注册,观察者希望在消息发布到MessageBoard时得到通知。当消息被添加到MessageBoard时,它将遍历其观察者列表,并通知他们发生了事件。

认为Twitter。当你说你想关注某人时,Twitter会把你添加到他们的关注者列表中。当他们发送一条新的推文时,你会在输入中看到它。在这种情况下,你的Twitter账户是观察者,你关注的人是可观察对象。

这个类比可能并不完美,因为Twitter更可能是一个Mediator。但它说明了这一点。

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

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

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

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

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

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

简单来说(因为其他答案都是参考了所有的官方设计模式,所以更多的细节可以参考它们):

如果你想让一个类被程序生态系统中的其他类监视,你说你想让这个类是可观察的。也就是说,它的状态可能会有一些变化,你想要广播给程序的其余部分。

现在,要做到这一点,我们必须调用某种方法。我们不希望Observable类与感兴趣观察它的类紧密耦合。它不关心它是谁,只要它满足一定的标准。(假设这是一个广播电台,它并不关心谁在收听,只要他们把调频收音机调到他们的频率)。为了实现这一点,我们使用一个称为观察者的接口。

因此,Observable类将有一个观察者列表(例如,实现你可能拥有的观察者接口方法的实例)。每当它想要广播一些东西时,它就会一个接一个地在所有观察者上调用这个方法。

结束谜题的最后一件事是Observable类如何知道谁感兴趣? 因此,Observable类必须提供某种机制来允许observer注册他们的兴趣。像addObserver(Observer o)这样的方法在内部将观察者添加到观察者列表中,这样当有重要的事情发生时,它会循环遍历列表,并调用列表中每个实例的观察者接口的各自通知方法

在面试中,他们可能没有明确地问你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()传递)。

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

MyObserver作为观察者接口

interface MyObserver {


void update(MyObservable o, Object arg);
}

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


// ...
}

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


}

定义

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

例子

  1. 比方说,你的永久地址改变了,那么你需要通知护照当局和pan卡当局。所以这里护照当局和泛卡当局是观察者,而你是受试者。

  2. 在Facebook上也一样,如果你订阅了某个人,那么无论何时有新的更新发生,你都会收到通知。

何时使用:

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

  2. 当对象不知道它有多少观察者时。

  3. 当一个对象应该能够通知其他对象而不知道对象是谁时。

步骤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

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

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

数据绑定中,这可能是一个有用的例子,假设你有一些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 < / p >

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

文章摘录如下:

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

教科书定义:观察者模式定义了对象之间的一对多依赖关系,这样当一个对象改变状态时,它的所有依赖项都会被自动通知和更新。

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

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

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

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