在软件系统中,当一个对象的行为依赖另外一个对象的状态时,观察者模式就很有用。若不使用观察者模式,实现类似的功能,需要在一个线程中不断监听对象状态的变化。
在一个复杂的系统中,可能会因此开启很多线程,这将使系统性能产生额外的负担。
观察者模式的意义也在于此,它可以在单线程中,在自身状态发生变化时,及时通知所依赖的对象。
以下使用一个例子来说明。
AbstractSubject抽象主题对象
/**
* 抽象主题类。模拟在修改主题的text属性时,通知所有观察者。
* Created by j.tommy on 2017/9/15.
*/
public abstract class AbstractSubject {
// 主题属性
String text;
// 添加观察者
public abstract void addObserver(IObserver observer);
// 删除观察者
public abstract void removeObserver(IObserver observer);
// 通知所有观察者
abstract void inform();
// 设置主题属性
public abstract void setText(String text);
}
具体主题对象ConcreteSubject
/**
* Created by j.tommy on 2017/9/15.
*/
public class ConcreteSubject extends AbstractSubject {
private final Vector<IObserver> observers = new Vector<IObserver>();
public void addObserver(IObserver observer) {
if (null != observer) {
observers.addElement(observer);
}
}
public void removeObserver(IObserver observer) {
if (null != observer) {
observers.removeElement(observer);
}
}
void inform() {
Event event = new Event();
event.setMsg(text);
// 通知所有观察者
for (IObserver observer : observers) {
observer.changeEvent(event);
}
}
// 设置主题属性,并通知所有观察者
public void setText(String text) {
this.text = text;
System.out.println(this.getClass().getName() + " setText. Text is [" + text + "].");
inform();
}
}
在具体的观察者实现类中,维护了一个观察者队列,并提供了添加和删除观察者的方法。在自身状态(text属性)发生变化时,通知所有观察者。
观察者接口对象IObserver
/**
* 观察者接口。
* Created by j.tommy on 2017/9/15.
*/
public interface IObserver {
// 给主题回调的方法
public void changeEvent(Event event);
}
具体的观察者ConcreateObserver
/**
* Created by j.tommy on 2017/9/15.
*/
public class ConcreateObserver implements IObserver {
private String name;
public ConcreateObserver(String name) {
this.name = name;
}
@Override
public void changeEvent(Event event) {
System.out.println(this.name + " received subject event. msg=" + event.getMsg());
}
}
主题对象属性text发生变化时,通知观察者的方法参数Event
/**
* Created by j.tommy on 2017/9/15.
*/
public class Event {
private String msg;
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
}
测试类
/**
* Created by j.tommy on 2017/9/15.
*/
public class Main {
public static void main(String[] args) {
// 构造一个主题
AbstractSubject subject = new ConcreteSubject();
// 添加2个观察者
subject.addObserver(new ConcreateObserver("observer-1"));
subject.addObserver(new ConcreateObserver("observer-2"));
// 对主题对象的一个属性设值
subject.setText("hello");
System.out.println("==================");
subject.setText("你好");
}
}
测试结果:
观察者模式如此常用,以至于JDK内部就为我们开发人员提供了一套观察者模式的实现。
在java.util包中,包括Observable类和Observer接口。
在Observable中,已经实现了主要的功能,包括添加观察者、删除观察者、通知观察者。
在Observer接口中,定义了update方法,它会在Observable中的nofityObservers方法中被调用,以获得最新的状态变化。
我们只需要继承Observable、并实现Observer接口即可。
下面仍然是实现上面例子的功能,但这里使用JDK提供的Observable和Observer。
具体主题类:
/**
* Created by j.tommy on 2017/9/15.
*/
public class MyJdkObservable extends Observable {
private String name;
public void setName(String name) {
this.name = name;
this.setChanged();
this.notifyObservers();
}
public String getName() {
return this.name;
}
}
具体观察者:
/**
* Created by j.tommy on 2017/9/15.
*/
public class MyJdkObserver implements Observer {
private String name;
public MyJdkObserver(String name) {
this.name = name;
}
@Override
public void update(Observable o, Object arg) {
if (o instanceof MyJdkObservable) {
MyJdkObservable myJdkObservable = (MyJdkObservable) o;
System.out.println(this.name + " received event.MyJdkObservable.name=" + myJdkObservable.getName());
}
}
}
测试代码:
MyJdkObservable myJdkObservable = new MyJdkObservable();
myJdkObservable.addObserver(new MyJdkObserver("observer-1"));
myJdkObservable.addObserver(new MyJdkObserver("observer-2"));
myJdkObservable.setName("hello");
System.out.println("===================");
myJdkObservable.setName("你好");
测试结果:
在JDK中,观察者模式也得到的普遍的应用。一个典型的例子就是JButton。JButton继承自AbstractButton,AbstractButton中维护着一组监听器,它们就扮演着观察者的角色。
参考《Java程序性能优化-让你的Java程序更快、更稳定》(葛一宁等编著)。