描述:
在设计一组对象与它们所依赖的对象之间一致(同步)的交流模型时,观察者模式(Observer Pattern)很有用。它可以使对象的状态与它们所依赖的对象的状态保持同步。这组对象指的是观察者(Observer),它们所依赖的对象称为主题(Subject)。为了实现观察者(Observer)的状态与主题(Subject)保持同步,观察者模式(Observer Pattern)
推荐采用发布者--订阅者(publisher--subscriber)模型,以使这组观察者(Observer)和主题(Subject)对象之间有清晰的界限。
典型的观察者(Observer)是一个依赖于或者关注于主题对象的状态的对象。一个主题可以有一个或者多个观察者。这些观察者在主体的状态发生变化时,需要得到通知。
由于给定主体的观察者链表需要动态的变化,因此一个主题不能维护一个静态的观察者链表。因此关注于主题状态的任何对象都需要明确地注册自己为主体的一个观察者。主题状态发生的变化,都需要通知所有的以注册的观察者。从主题接到通知以后,每一个观察者查询主题,使自己的状态与主题的同步。因此一个主题扮演着发布者的角色,发布信息到所有的以订阅的观察者。
换句话说,主题和它的观察者之间包含了一对多的关系。当主题的实例的状态发生变化时,所有的依赖于它的观察者都会得到通知并更新自己。每一个观察者对象需要向主题注册,当主题的状态发生变化的时候得到通知。一个观察者可以注册或者订阅多个主题。当观察者不希望再得到通知时,它可以向主题进行注销。
为了实现这种机制:
(1) 主题需要为注册和注销通知提供一个接口。
(2) 下面的两点也需要满足:
A、 拉模型(In the pull model)--主题需要提供一个接口,可以使观察者查询主题获得需要的状态信息来更新自己的状态。
B、 推模型(In the push model)--主题发送观察者可能关注的状态信息。
(3) 观察者需要提供一个可以从主题接受通知的接口。
类图(图33.1)描述了为满足于以上需求,不同类的结构和它们之间的关联关系。
从这个类图可以看到:
(1) 所有的主题需要提供一个类似于Observable接口的实现。
(2) 所有的观察者需要提供一个类似于Observer接口的实现。
在应用观察者模式时,有几种变体。这就会产生不同类型的主题--观察者模式,例如,观察者仅关注主体特定类型的变化等。
增加新的观察者:
应用观察者模式以后,在不影响主题类的情况下,可以动态的加入不同的观察者。同样,主题的状态变化逻辑改变时,观察者也不会受到影响
例子:
观察者类:
class SimpleObserver implements PropertyChangeListener {
public void propertyChange(PropertyChangeEvent evt) {
if (evt.getPropertyName().equals("Domain.id")) {
System.out.println("哦也也" + evt.getNewValue());
}
}
//客户端,实例化观察者,主题对象,并且主题注册观察者
public static void main(String[] args) {
SimpleObserver observer = new SimpleObserver();
Domain domain = new Domain();
domain.addPropertyChangeListener(observer);
domain.setId("Id");
}
}
主题类:
class Domain {
protected String id;
protected PropertyChangeSupport listeners = new PropertyChangeSupport(this);
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
firePropertyChange("Domain.id", null, id);
}
public void addPropertyChangeListener(PropertyChangeListener listener) {
listeners.addPropertyChangeListener(listener);
}
public void firePropertyChange(String propName, Object oldValue, Object newValue) {
listeners.firePropertyChange(propName, oldValue, newValue);
}
public void removePropertyChangeListener(PropertyChangeListener listener) {
listeners.removePropertyChangeListener(listener);
}
}