我们什么时候应该使用Observer和Observable
一位面试官问我:
Observer
和Observable
是什么,我们应该什么时候使用它们?
我没有意识到这些条款,所以当我回到家时,我开始使用关于Observer
和Observable
Googlesearch,并从不同的资源中find了一些要点:
1)
Observable
是一个类,Observer
是一个接口。2)
Observable
类保持观察者列表。3)当一个Observable对象被更新时,它调用每个Observers的
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!"); } }
但我不明白为什么我们需要Observer
和Observable
? 什么是setChanged()
和notifyObservers(message)
方法?
你有一个学生和一个MessageBoard的具体例子。 学生通过将其自身添加到希望在将新消息发布到消息板时被通知的观察者列表中进行注册。 当消息被添加到消息板时,它遍历其观察者列表,并通知他们事件已经发生。
想想Twitter。 当你说你想跟随某人时,Twitter会将你添加到他们的追随者列表中。 当他们发送新的推文时,您会在input中看到它。 在这种情况下,你的Twitter账号就是Observer,而你所关注的人就是Observable。
这个比喻可能并不完美,因为Twitter更有可能成为调解人。 但它说明了这一点。
用非常简单的话来说(因为其他答案都是指你所有的官方devise模式,所以请看他们的进一步细节):
如果你想有一个由你的程序的生态系统中的其他类监控的类,你说你希望这个类是可观察的。 也就是说,你可能会想要播放其他节目的状态。
现在,要做到这一点,我们必须调用某种方法。 我们不希望Observable类与有兴趣观察它的类紧密耦合。 只要满足一定的标准,它并不关心它是谁。 (想象一下,这是一个广播电台,只要他们调频的调频收音机,它并不关心谁在收听。 为了达到这个目的,我们使用一个称为Observer的接口。
因此,Observable类将有一个Observers列表(即实现Observer接口方法的实例)。 每当想要广播某些东西的时候,它只是一个接一个地在所有的观察者上调用这个方法。
closures这个难题的最后一件事是,Observable类如何知道谁有兴趣? 所以观察者必须提供一些机制让观察者注册他们的兴趣。 诸如addObserver(Observer o)
内部将Observer添加到观察者列表中,以便当重要事件发生时,它循环遍历列表,并调用列表中每个实例的Observer接口的相应通知方法。
在采访中,他们可能并没有明确地询问java.util.Observer
和java.util.Observable
而是关于generics的概念。 这个概念是一种devise模式,Java碰巧提供了直接开箱即用的支持,以帮助您在需要时快速实施。 所以我build议你理解这个概念,而不是实际的方法/类(你可以在需要的时候查看)。
UPDATE
为了回应您的评论,实际的java.util.Observable
类提供了以下function:
-
维护
java.util.Observer
实例的列表。 有兴趣收到通知的新实例可以通过addObserver(Observer o)
,并通过deleteObserver(Observer o)
删除。 -
维护一个内部状态,指定对象自从上次通知观察者以来是否发生了变化。 这样做很有用,因为它将您所说的
Observable
发生变化的部分与通知发生变化的部分分开。 (例如,如果你有多个变化发生,你只想在过程结束而不是在每一个小步骤通知它是有用的。 这是通过setChanged()
。 所以当你把某些东西改变成Observable
时候,你可以调用它,并且希望剩下的Observers
最终知道它。 -
通知所有的观察者,特定的
Observable
已经改变了状态。 这是通过notifyObservers()
。 这会在继续进行通知之前检查对象是否已经实际更改(即调用setChanged()
)。 有两个版本,一个没有参数,一个有Object
参数,以防你想通过一些额外的信息。 在内部发生的事情是,它只是迭代Observer
实例列表,并为它们中的每一个调用update(Observable o, Object arg)
方法。 这告诉Observer
哪个Observable对象发生了变化(您可能正在观察多个Object arg
),而额外的Object arg
可能会携带一些额外的信息(通过notifyObservers()
传递notifyObservers()
。
定义
当对象之间存在一对多关系时,使用观察者模式,例如,如果修改了一个对象,则将自动通知其相关对象,并对所有相关对象进行相应的更改。
例子
-
可以说,你的永久地址是变化的,那么你需要通知护照权威和潘卡权威。所以这里的护照权威和潘卡权威是观察员,你是一个主题。
-
在Facebook上,如果你订阅某个人,那么每当有新的更新发生时,你将被通知。
何时使用它:
1. When one object changes its state,then all other dependents object must automatically change their state to maintain consistency 2. When subject doesn't know about number of observers it has. 3. When an object should be able to notify other objects without knowing who objects are.
步骤1
创build主题类。
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步
创buildObserver类。
Observer.java
public abstract class Observer { protected Subject subject; public abstract void update(); }
第3步
创build具体的观察者类
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步
validation输出。
第一次状态变化:15
hexstring:F
八进制string:17
二进制string:1111
第二个状态变化:10
hexstring:A
八进制string:12
二进制string:1010
它们是观察者devise模式的一部分 。 通常,一个或多个远程者会获知有关可观察到的变化的信息。 这是一个“事情”发生的地方,你作为程序员可以定义什么“东西”的含义。
当使用这种模式时,你将两个实体从另一个中分离出来 – 观察者变成可插入的。
观察者又名callback在Observable注册。
它用于通知例如在某个时间点发生的事件。 它被广泛用于Swing,Ajax,GWT等调度UI事件的操作(button点击,文本框更改等)。
在Swing中,你可以find像addXXXListener(Listener l)这样的方法,在GWT中你有(asynchronous)callback。
由于观察者列表是dynamic的,观察者可以在运行时注册和取消注册。 当使用接口时,将观察者与观察者分离也是一个很好的方法。
如果面试者要求不使用Observer类和接口来实现Observerdevise模式 ,那么可以使用下面的简单例子!
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 { public void update(MyObservable o, Object arg) { System.out.println("Message board changed: " + arg); } }
“我试图弄清楚,为什么我们需要Observer和Observable”
正如前面已经提到的答案,他们提供了订阅观察者的方式来接收可观察的自动通知。
一个可能有用的示例应用程序是数据绑定 ,假设您有一些UI可以编辑某些数据,并且希望UI在数据更新时作出反应,您可以使数据可观察,并订阅UI组件数据
Knockout.js是一个MVVM的JavaScript框架,有一个很好的入门教程,看到更多的观察行动,我真的build议通过教程。 http://learn.knockoutjs.com/
我也在Visual Studio 2008开始页面中find了这篇文章( 观察者模式是模型视图控制器(MVC)开发的基础 ) http://visualstudiomagazine.com/articles/2013/08/14/the-observer-pattern-in -net.aspx
我在这里写了一个观察者模式的简短描述: http : //www.devcodenote.com/2015/04/design-patterns-observer-pattern.html
post的一个片段:
观察者模式:它基本上build立了对象之间的一对多关系,并且在相互依赖的对象之间具有松耦合的devise。
TextBook定义:观察者模式定义了对象之间的一对多依赖关系,以便当一个对象改变状态时,所有的依赖关系都会被自动通知和更新。
例如,考虑一个Feed通知服务。 订阅模型是最好的了解观察者模式。
当对象之间存在一对多关系时使用观察者模式,例如,如果修改了一个对象,则会自动通知其相关对象。