1. 类图
- Subject:目标对象
- 一个目标可以被多个观察者观察
- 目标提供观察者订阅和取消的维护
- 目标对象发生变化,通知所有有效观察者
- Observer:定义观察者接口,提供目标对象变化时,对应观察者的更新方法
- ConcreteObserver:具体观察者实现
- ConcreteSubject:具体目标对象实现
2. 示例
修改目标的数据,触发相应通知,联动调用观察者的方法
2.1 目标对象
知道所有的观察者,并提供和维护观察者的订阅与退订逻辑
public class Subject {
private List<Observer> readers = new ArrayList<>();
// 订阅报纸
public void subscribe(Observer reader){
System.out.println(String.format("读者【%s】订阅了报纸", ((Reader) reader).getName()));
readers.add(reader);
}
// 退订报纸
public void unsubscribe(Observer reader){
System.out.println(String.format("读者【%s】退订了报纸", ((Reader) reader).getName()));
readers.remove(reader);
}
// 向所有读者推送报纸内容
public void notifyAllReader(){
readers.forEach(reader -> reader.read(this));
}
}
2.2 具体的目标对象
着重描述通知的内容
public class Newspaper extends Subject {
// 报纸内容
private String content;
public String getContent() {
return content;
}
public void setContent(String content) {
// 报纸内容更新
this.content = content;
// 向所有读者推送报纸内容
notifyAllReader();
}
}
2.3 观察者
public interface Observer {
// 报纸阅读
void read(Subject subject);
}
2.4 具体的观察者
public class Reader implements Observer {
private String name;
public Reader() {}
public Reader(String name) {this.name = name;}
public String getName() {
return name;
}
@Override
public void read(Subject subject) {
System.out.println(String.format("读者%s正在阅读最新一期的报纸,报纸主题为:%s",
name, ((Newspaper) subject).getContent()));
}
}
2.5 客户端
public class Client {
public static void main(String[] args) {
// 初始化读者
Observer reader1 = new Reader("张三");
Observer reader2 = new Reader("李四");
// 报纸订阅
Newspaper subject = new Newspaper();
subject.subscribe(reader1);
subject.subscribe(reader2);
// 报纸更新
subject.setContent("如何使用观察者模式");
// 退订
subject.unsubscribe(reader1);
// 报纸更新
subject.setContent("如何更好的使用观察者模式");
}
}
3. 优点
- 实现了观察者与目标之间的抽象耦合
- 目标对象与观察者之间可以动态联动
4. 缺点
- 目标对象发生变化时,都会触发观察者的update方法,无论观察者是否需要