什么是观察者模式
观察者模式:定义对象之间的一对多依赖,当一个对象的改变状态时,它的依赖者都会收到通知并自动更新。这里就用报社、人来分析,如果有人想看报纸就可以向报社订阅,如果已经订阅的人不想看报纸可以向报社注销,而对于报社而言,它只会把报纸发给订阅的人群,这里的报社就是观察者模式中的主题(Subject),人就是观察者(Observer),观察者向主题注册自己就可以在主题改变时收到通知。
UML图
代码实现
/**
* 观察者模式的主题,用于注册、移除、通知观察者
*/
public interface Subject {
/**
* 新增观察者
*/
void registerObserver(Observer observer);
/**
* 移除观察者
*/
void removeObserver(Observer observer);
/**
* 通知观察者
*/
void notifyObserver(String newspaperName);
}
/**
* 观察者接口类
*/
public interface Observer {
/**
* 被通知时做的操作
*/
void update(String newspaperName);
}
上面时观察者模式的两个核心类,下面时具体的应用,首先是主题实现类-NewspaperOffice,observerList 保存所有的观察者,
import java.util.ArrayList;
import java.util.List;
public class NewspaperOffice implements Subject{
private List<Observer> observerList = new ArrayList<>();
@Override
public void registerObserver(Observer observer) {
observerList.add(observer);
}
@Override
public void removeObserver(Observer observer) {
observerList.remove(observer);
}
/**
* 通知观察者们
*/
@Override
public void notifyObserver(String newspaperName) {
observerList.forEach((b) -> b.update(newspaperName));
}
}
这里是具体的观察者,也就是被通知的对象
/**
* 观察者A
*/
public class CustomerA implements Observer{
private Subject subject;
public CustomerA(Subject subject) {
this.subject = subject;
subject.registerObserver(this);
}
@Override
public void update(String newspaperName) {
System.out.println("CustomerA:《" + newspaperName + "》发布了");
}
}
/**
* 观察者B
*/
public class CustomerB implements Observer {
private Subject subject;
public CustomerB(Subject subject) {
this.subject = subject;
subject.registerObserver(this);
}
@Override
public void update(String newspaperName) {
System.out.println("CustomerB:《" + newspaperName + "》发布了");
}
}
测试上面写的简易观察者模式实现
public class ObserverTest {
public static void main(String[] args) {
Subject subject = new NewspaperOffice();
new CustomerA(subject);
// 注册观察者B
new CustomerB(subject);
// 通知观察者们
subject.notifyObserver("日报A");
System.out.println("========================================");
subject.notifyObserver("日报B");
}
}
测试结果
总结
从上面的例子分析,主题和观察则都是接口,主题通过接口通知依赖它的所有观察者做某个操作(广播通信),只要知道具体对象的列表,而不需要知道某个具体的对象,上面例子NewspaperOffice只需拥有Observer数组,至于具体的某个Observer并不关注,降低了对象之间的耦合度,这里也是设计原则"针对接口编程,不针对实现编程"的体现。