什么是Observer
和Observable
以及我们何时应该使用它们?
我不知道这些条款,所以当我回到家并开始使用谷歌搜索Observer
和Observable
时,我发现了来自不同资源的一些观点:
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
?什么是Observable
和setChanged()
方法?
答案 0 :(得分:250)
您有一个学生和MessageBoard的具体示例。学生通过将自己添加到希望在将新消息发布到MessageBoard时得到通知的观察者列表进行注册。当消息被添加到MessageBoard时,它会遍历其观察者列表并通知他们事件发生。
想想Twitter。当您说想跟随某人时,Twitter会将您添加到他们的关注者列表中。当他们发送新推文时,您会在输入中看到它。在这种情况下,您的Twitter帐户是Observer,您关注的人是Observable。
类比可能并不完美,因为Twitter更有可能成为调解员。但它说明了这一点。
答案 1 :(得分:54)
用非常简单的术语(因为其他答案指的是所有官方设计模式,所以请查看它们以获取更多详细信息):
如果您希望有一个由您的程序生态系统中的其他类监视的类,则表示您希望该类是可观察的。即它的状态可能会有一些变化,你想要广播到程序的其余部分。
现在,要做到这一点,我们必须调用某种方法。我们不希望Observable类与有兴趣观察它的类紧密耦合。只要满足某些标准,它就不关心它是谁。 (想象一下,这是一个广播电台,只要他们在频率上调谐FM收音机就不关心谁在听。)为此,我们使用一个称为Observer的接口。
因此,Observable类将有一个Observers列表(即实现您可能具有的Observer接口方法的实例)。每当它想要播放某些内容时,它就会一个接一个地调用所有观察者的方法。
关闭这个难题的最后一件事是Observable类将如何知道谁感兴趣?
所以Observable类必须提供一些机制来允许Observers注册他们的兴趣。诸如addObserver(Observer o)
之类的方法在内部将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()
传递。
答案 2 :(得分:35)
<强>定义强>
当对象之间存在一对多关系时使用Observer模式,例如,如果修改了一个对象,则会自动通知其依赖对象,并对所有依赖对象进行相应的更改。
<强>实施例强>
让我们说,您的永久地址已更改,然后您需要通知护照管理局和泛卡权限。所以这里的护照权限和泛卡权限是观察员,你是一个主题。
在Facebook上,如果您订阅某人,那么无论何时发生新的更新,您都会收到通知。
何时使用:
当一个对象更改其状态时,所有其他依赖对象必须自动更改其状态以保持一致性
当受试者不知道其拥有的观察人数时。
当一个对象应该能够在不知道对象是谁的情况下通知其他对象时。
第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,您可以使用以下简单示例!
interface MyObserver {
void update(MyObservable o, Object arg);
}
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;
}
// ...
}
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?
但是,你可能仍会得到关于他们的面试问题......