Java 什么时候我们应该使用观察者和可观察者?
一位采访者问我: 什么是Java 什么时候我们应该使用观察者和可观察者?,java,design-patterns,observable,observer-pattern,observers,Java,Design Patterns,Observable,Observer Pattern,Observers,一位采访者问我: 什么是observator和observatable以及什么时候应该使用它们 我不知道这些术语,所以当我回到家开始用谷歌搜索observator和observatable时,我从不同的资源中找到了一些要点: 1) 是一个类,也是一个接口 2) observeable类维护一个observests的列表 3) 当一个可观察的对象被更新时,它调用其每个观察者的update()方法来通知它已被更改 我发现这个例子: import java.util.Observable; impor
observator
和observatable
以及什么时候应该使用它们
我不知道这些术语,所以当我回到家开始用谷歌搜索observator
和observatable
时,我从不同的资源中找到了一些要点:
1) 是一个类,也是一个接口
2) observeable
类维护一个observest
s的列表
3) 当一个可观察的对象被更新时,它调用其每个观察者的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!");
}
}
但我不明白为什么我们需要观察者
和可观察者
?什么是setChanged()
和notifyobservators(message)
方法?您有一个学生和留言板的具体示例。学生通过将自己添加到希望在新消息发布到留言板时得到通知的观察者列表中进行注册。当一条消息被添加到留言板时,它会在观察者列表上迭代,并通知他们事件发生了
想想推特。当你说你想跟踪某人时,Twitter会将你添加到他们的关注者列表中。当他们发送一条新的推文时,你会在你的输入中看到它。在这种情况下,您的Twitter帐户是观察者,您跟踪的人是被观察者
这个类比可能并不完美,因为推特更可能是一个调解人。但它说明了这一点。它们是系统的一部分。
通常情况下,一个或多个OBerver会被告知一个可观察对象的更改。这是一个“某物”发生的通知,作为程序员,您可以定义“某物”的含义
当使用此模式时,您将两个实体彼此分离-观察者成为可插拔的。观察者a.k.a回调在Observable注册
它用于通知(例如)在某个时间点发生的事件。它广泛应用于Swing、Ajax和GWT中,用于调度UI事件等操作(按钮单击、文本字段更改等)
在Swing中可以找到像addXXXListener(Listener l)这样的方法,在GWT中可以找到(异步)回调
由于观察者列表是动态的,观察者可以在运行时注册和注销。这也是一种很好的方法,可以将可观察对象与观察者分离,因为使用了接口。用非常简单的术语来说(因为其他答案指的是所有官方设计模式,所以请查看它们以了解更多细节):
如果您想拥有一个由程序生态系统中的其他类监视的类,您可以说您希望该类是可观察的。也就是说,它的状态可能会发生一些变化,您可能希望向节目的其他部分广播这些变化
现在,要做到这一点,我们必须调用某种方法。我们不希望可观察的类与有兴趣观察它的类紧密耦合。它不在乎它是谁,只要它满足某些标准。(假设这是一个广播电台,只要他们的调频收音机调到他们的频率,它就不在乎谁在听)。为了实现这一点,我们使用了一个称为观察者的接口
因此,Observable类将有一个观测者列表(即实现您可能有的观测者接口方法的实例)。每当它想要广播某个内容时,它都会对所有观察者逐个调用该方法
最后要解决的问题是,可观察类如何知道谁感兴趣?
因此,Observable类必须提供某种机制,允许观察者注册他们的兴趣。一种方法,例如addObserver(Observer o)
在内部将观察者添加到观察者列表中,以便在发生重要事件时,它在列表中循环并调用列表中每个实例的观察者接口的相应通知方法
这可能是因为在采访中,他们没有明确询问您关于java.util.Observer
和java.util.Observable
的问题,而是关于一般概念的问题。这个概念是一个设计模式,Java恰好提供了对开箱即用的直接支持,以帮助您在需要时快速实现它。因此,我建议您理解这个概念,而不是实际的方法/类(您可以在需要时查找它们)
更新
针对您的评论,实际课程提供以下设施:
维护java.util.Observer
实例列表。对通知感兴趣的新实例可以通过addObserver(Observer o)
添加,也可以通过deleteObserver(Observer o)
删除
维护内部状态,指定自上次通知观察者以来对象是否已更改。这是很有用的,因为它将表示可观察的已更改的部分与通知更改的部分分开。(例如,如果您有多个更改发生,并且您只想在流程结束时通知,而不是在每个小步骤时通知,则此功能非常有用)。这是通过setChanged()
完成的。因此,当您将某个内容更改为可观察的时,您只需调用它,您希望其他观察者最终了解它
通知所有观察者特定的可观察的
状态已更改。这是通过notifyobserver()
完成的。这将检查对象在继续通知之前是否已实际更改(即调用了setChanged()
)。有两个版本,一个没有参数,另一个带有对象
参数,以防您希望在通知中传递一些额外信息。在内部发生的是
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);
}
}
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();
}
}
public abstract class Observer {
protected Subject subject;
public abstract void update();
}
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() ) );
}
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() ) );
}
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() );
}
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);
}