OO原则
- 封装变化
- 多用组合,少用继承
- 针对接口编程,不针对实现编程
- 为对象之间的松耦合设计努力
观察者模式
- 对象之间定义一对多的依赖,当一个subject对象改变状态时,依赖它的对象会收到通知,并自动更新
- 应用:JavaBeans / RMI / GUI
- 实现:java.util.Observable的问题在于 subject不是接口,而是抽象类
- 细节:push/pull两种方式,push更友好;多个观察者不应该依赖特定的通知次序
- JDK自带的观察者observable并不灵活,可以自己实现
自己实现最简单的观察者
public interface Subject {
void registerObserver(Observer o);
void removeObserver(Observer o);
void notifyObservers();
}
public interface Observer {
void update(float temp, float humidity, float pressure);
}
public class SubjectIml implements Subject {
private List<Observer> observers;
private float temperature;
private float humidity;
private float pressure;
public SubjectIml() {
observers = new ArrayList<Observer>();
}
public void registerObserver(Observer o) {
observers.add(o);
}
public void removeObserver(Observer o) {
int i = observers.indexOf(o);
if (i >= 0) {
observers.remove(o);
}
}
public void notifyObservers() {
for (Observer o : observers) {
o.update(temperature, humidity, pressure);
}
}
public void measurementsChanged() {
notifyObservers();
}
public void setMeasurements(float temperature, float humidity, float pressure) {
this.temperature = temperature;
this.humidity = humidity;
this.pressure = pressure;
measurementsChanged();
}
}
缺点:
- 每次变更,直接push给观察者,没有在合适的时候推送
- 缺少pull的方式
- 可能有线程安全问题
JDK自带的观察者
-
notifyObservers方法:根据changed决定是否通知
public void notifyObservers(Object arg) {
/*
* a temporary array buffer, used as a snapshot of the state of
* current Observers.
*/
Object[] arrLocal;synchronized (this) { /* We don't want the Observer doing callbacks into * arbitrary code while holding its own Monitor. * The code where we extract each Observable from * the Vector and store the state of the Observer * needs synchronization, but notifying observers * does not (should not). The worst result of any * potential race-condition here is that: * 1) a newly-added Observer will miss a * notification in progress * 2) a recently unregistered Observer will be * wrongly notified when it doesn't care */ if (!changed) return; arrLocal = obs.toArray(); clearChanged(); } for (int i = arrLocal.length-1; i>=0; i--) ((Observer)arrLocal[i]).update(this, arg);
}
-
pull 方式:null代表没有更新,观察者需要调用主题对象的get()方法
public void notifyObservers() {
notifyObservers(null);
} -
缺点:不是接口,是一个class