六大方面
- 目标与观察者之间的关系
一个观察者–多个目标
多个观察者–一个目标 - 单项依赖
观察者依赖目标,而不是目标依赖观察者。观察者始终处于被动地位,等待目标传值。 - 命名建议
目标接口–后面跟Subject
观察者接口–后面跟Observer
观察者接口更新方法–建议为update - 触发通知的时机
一般是完成了状态维护后出发。不能够先通知,后改变状态。 - 观察者模式的调用顺序
- 通知的顺序
观察者的两种实现方式——推模型&拉模型
推模型
目标对象主动向观察者推送目标的详细信息,推送的信息通常是目标对象的全部或部分数据。
拉模型
目标对象在通知观察者的时候,值传递少量信息。如果观察者需要更具体的信息,有观察者主动到目标对象中获取,相当于是观察者从目标对象中拉取数据。一般这种模型的实现中,会把目标对象自身通过update方法传递给观察者。
两种模型的比较:
推模型是假定目标对象知道观察者需要的数据。
拉模型是目标对象不知道观察者具体需要什么数据,就把自己传给观察者,由观察者来取值。
推模型会使观察者对象难以复用。
拉模型update方法的参数是目标对象本身,可以按需获取。
Java自带的观察者接口
import java.util.Observable;
import java.util.Observer;
class ConcreteWeatherSubject extends Observable {
//天气情况的内容
private String content;
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
//天气情况有了,就要通知所有的观察者
this.setChanged();
this.notifyObservers(content); //推模型
}
}
class ConcreteObserver implements Observer {
private String observerName;
@Override
public void update(Observable o, Object arg) {
//推模型
System.out.println(observerName + "收到了消息,目标推送过来的是" + arg);
//拉模型
System.out.println(observerName + "收到了消息,拉取的内容是" + ((ConcreteWeatherSubject)o).getContent());
}
public String getObserverName() {
return observerName;
}
public void setObserverName(String observerName) {
this.observerName = observerName;
}
}
public class WeatherDemo {
public static void main(String[] args) {
ConcreteWeatherSubject subject = new ConcreteWeatherSubject();
ConcreteObserver girl = new ConcreteObserver();
girl.setObserverName("女朋友");
ConcreteObserver mum = new ConcreteObserver();
mum.setObserverName("老妈");
subject.addObserver(girl);
subject.addObserver(mum);
subject.setContent("天气晴,气温28度");
}
}
观察者模式的应用场景:
一、当一个抽象模型有两个方面,其中一个方面的操作依赖于另一个方面的状态变化时。
二、如果再更改一个对象的时候,需要同时连带改变其他对象,而且不知道究竟应该有多少对象需要被连带改变。
三、当一个对象必须通知其他对象,但又希望这个对象和其他被通知的对象是松散耦合。