- 概述
java.util包内包含最基本的Observer接口和Observable类,这和上一节的Observer接口与Subject接口很相似。Observer接口和Observable类使用上更方便。因为许多功能已经事先准备好了,甚至可以使用推(push)或拉(pull)的方式传递数据。但是Observable类也有一些黑暗面,有时候我们还是需要实现自己的主题接口。 UML
说明:
java内置的观察者模式与上一节介绍的观察者区别在于1) Observable是一个类而不是一个接口,ConcreteSubject扩展了它并且继承了一系列增加、删除、通知等方法。Observable中添加了一个changed成员变量,和相关的setChanged()、clearChanged()、hasChanged()方法,用来标记状态的改变情况,当changed值为true时调用notifyObservers()方法才会更新观察者。(这样做是很有必要的,可以使设计更有弹性,我们可以在更适当的时候更新观察者)。
2) Observable类虽然提供了有用的功能但是它的实现也存在许多问题,限制了它的使用和复用。首先Observable是一个类而不是一个接口,并且它没有实现一个接口,我们必须设计一个类去继承它,如果某类需要同时具有Observable和另一个超类的行为,就会陷入两难,毕竟java不支持多重继承,这限制了Observable的复用潜力。再者Observable中状态相关的关键操作(例如setChanged()方法)是protected的,这意味着除非继承自Observable,否则我们无法创建Observable实例并组合到自己的对象中来。这个设计违反了“多用组合,少用继承”的设计原则。
3) Observer接口基本没有太大的改变,只是方法签名变了,如果想“推”数据给观察者,可以把数据当做数据对象传递给notifyObservers(arg)方法,否则观察者就必须从可观察者对象中“拉”数据(下面的实现是一个“拉”数据的例子)。
实现
/**
* 下面的实现省略了包名和这两个import操作
*/
import java.util.Observable;
import java.util.Observer;
/**
* 子类-具体的可观察者(主题)
*/
public class ConcreteSubject extends Observable {
private String message;
/**
* 更新消息
* 需要先调用setChanged()方法标记状态已经改变。
* 使用“拉”的方式:这里调用notifyObservers()没有传递数据对象。
*/
public void messageChanged() {
setChanged();
notifyObservers();
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
messageChanged();
}
}
/**
* 接口实现类-具体的观察者
*/
public class ConcreteObserver implements Observer {
/**
* 这里保存对subject的引用,是因为如果以后要取消注册,
* 已经有了对subject的引用会比较方便。
*/
private Observable observable;
public ConcreteObserver(Observable o) {
this.observable = o;
observable.addObserver(this);
}
@Override
public void update(Observable o, Object arg) {
if (o instanceof ConcreteSubject) {
ConcreteSubject ConcreteSubject = (ConcreteSubject) o;
System.out.println(ConcreteSubject.getMessage());
}
}
}
/**
* 测试类-观察者模式
*/
public class ObserverTest {
public static void main(String[] args) {
ConcreteSubject concreteSubject = new ConcreteSubject();
Observer o1 = new ConcreteObserver(concreteSubject);
Observer o2 = new ConcreteObserver(concreteSubject);
Observer o3 = new ConcreteObserver(concreteSubject);
concreteSubject.setMessage("Hello World !");
}
}
运行结果:
参考资料:
《Head First设计模式》