一位面试官问我:
什么是Observer
和Observable
?我们应该在什么时候使用它们
我不知道这些术语,所以当我回到家,开始在谷歌上搜索Observer
和Observable
时,我从不同的资源中找到了一些要点:
1)
Observable
是一个类,Observer
是一个接口。2)
Observable
类维护Observer
s的列表。3) 当
Observable
对象更新时,它会调用其每个Observer
的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)
方法的作用是什么?
您有一个Student和MessageBoard的具体示例。学生通过将自己添加到希望在向MessageBoard发布新消息时得到通知的观察者列表中进行注册。当消息被添加到MessageBoard时,它会遍历其观察者列表,并通知他们事件发生了。
想想推特吧。当你说你想关注某人时,推特会将你添加到他们的关注者列表中。当他们在中发送新的推文时,你会在输入中看到它。在这种情况下,你的推特账户是Observer,你关注的人是Observable。
这种类比可能并不完美,因为推特更有可能是一个中介。但它说明了这一点。
用非常简单的术语来说(因为其他答案都是指所有官方设计模式,所以请查看它们以了解更多详细信息):
如果你想要一个由程序生态系统中的其他类监控的类,你会说你希望这个类是可观察的。也就是说,它的状态可能会有一些变化,你想把这些变化广播给节目的其他部分。
现在,要做到这一点,我们必须调用某种方法。我们不希望Observable类与有兴趣观察它的类紧密耦合。只要它满足某些标准,它就不在乎它是谁。(想象一下,这是一个广播电台,它不在乎谁在听,只要他们有调频收音机调到自己的频率)。为了实现这一点,我们使用了一个接口,称为Observer。
因此,Observable类将有一个Observer列表(即,实现您可能拥有的Observer接口方法的实例)。每当它想广播某个内容时,它只会在所有观察者上一个接一个地调用该方法。
最后要解决的问题是Observable类如何知道谁感兴趣?因此,Observable类必须提供一些机制,允许观察者注册他们的兴趣。像addObserver(Observer o)
这样的方法在内部将Observer添加到Observer列表中,这样当发生重要事件时,它会在列表中循环,并调用列表中每个实例的Observer接口的相应通知方法。
可能是在面试中,他们没有明确问你关于java.util.Observer
和java.util.Observable
的问题,而是关于一般概念的问题。这个概念是一种设计模式,Java恰好直接提供开箱即用的支持,以帮助您在需要时快速实现它。因此,我建议您理解这个概念,而不是实际的方法/类(您可以在需要时查找它们)。
更新
作为对您评论的回应,实际的java.util.Observable
类提供了以下功能:
-
维护
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
,可能携带一些额外的信息(通过notifyObservers()
.
定义
当对象之间存在一对多关系时,会使用观察者模式,例如,如果修改了一个对象,则会自动通知其依赖对象,并对所有依赖对象进行相应的更改。
示例
-
假设您的永久地址发生了更改,那么您需要通知护照管理局和泛卡管理局。所以这里的护照管理局和泛卡管理局是观察员,你是一个主体。
-
在Facebook上,如果你订阅了某人,那么每当有新的更新发生时,你都会收到通知。
何时使用:
-
当一个对象更改其状态时,所有其他从属对象必须自动更改其状态以保持一致性
-
当受试者不知道观察者的数量时。
-
当一个对象应该能够在不知道对象是谁的情况下通知其他对象时。
步骤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和具体的observer对象。
Observer PatternMo.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
十六进制字符串:
八进制字符串:12
二进制字符串:1010
它们是Observer设计模式的一部分。通常,一个或多个观察者会被告知一个可观察的变化。这是一个"某事"发生的通知,作为程序员,你可以定义"某事"的含义。
当使用这个模式时,您将两个实体彼此解耦——观察者变成可插入的。
Observer a.k.回调在Observable中注册。
它用于通知例如某个时间点发生的事件。它广泛用于Swing、Ajax、GWT中,用于调度UI事件(按钮单击、文本字段更改等)上的操作。
在Swing中可以找到addXXXListener(Listener l)等方法,在GWT中可以找到(Async)回调。
由于观察者列表是动态的,观察者可以在运行时注册和注销。这也是一种很好的方法,可以将可观察的与观察者解耦,因为使用了接口。
如果面试官要求在不使用Observer类和接口的情况下实现Observer设计模式,您可以使用以下简单示例!
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);
}
}
"我试图弄清楚,为什么我们需要Observer和Observable">
正如前面的回答所述,它们提供了订阅观察者以接收可观察到的自动通知的方式。
这可能有用的一个示例应用程序是在数据绑定中,假设您有一些编辑某些数据的UI,并且您希望UI在数据更新时做出反应,您可以使数据可观察,并将UI组件订阅到数据
Knockout.js是一个MVVM javascript框架,它有一个很好的入门教程,为了看到更多的可观察性,我真的建议阅读该教程。http://learn.knockoutjs.com/
我还在VisualStudio2008的起始页上找到了这篇文章(观察者模式是模型-视图-控制器(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
文章摘录:
观察者模式:它本质上建立了对象之间的一对多关系,并在相互依赖的对象之间进行了松散耦合的设计。
TextBook定义:观察者模式定义了对象之间的一对多依赖关系,这样当一个对象改变状态时,它的所有依赖关系都会自动得到通知和更新。
以提要通知服务为例。订阅模型是理解观察者模式的最佳方法。
当对象之间存在一对多关系时,会使用观察者模式,例如如果修改了一个对象,则会自动通知其依赖对象。
由于Java9,这两个接口都不推荐使用,这意味着您不应该再使用它们了。请参阅Observer在Java 9中已弃用。我们应该用什么来代替它?
然而,你可能仍然会收到关于他们的面试问题。。。