观察者模式
1、观察者模式的动机
建立一种一对多的依赖关系,一种发生变化时通知其他对象跟着做出反应。这种发生变化的对象称为主题或者被观察者,被通知做出相应的对象称为观察者。观察者相互 独立,允许添加,删除;
2、观察者模式的定义
定义了对象间的一对多的依赖,这样一来,当一个对象发生改变时,他的所有依赖均会收到通知并自行更新。
常用场景如:发布--订阅,模型--视图,源--监听者等;
3、观察者模式的类结构图
模式中包含三个角色:主题类subject(接口或者抽象类),观察者接口observer,以及他们的具体实现类:
- 多个观察者依赖于主题对象;
- 主题控制一份数据,当数据状态发生变更时通知其所有观察者;
- 主题通过观察者接口方法通知观察者,观察者通过主题接口方法向主题中注册观察者;
满足的设计原则如下:
1、为了交互对象的松耦合设计而努力
松耦合的的设计之所以能够让我们建立有弹性的oo系统,能够应对变化是因为对象之间的相互依赖降到了最低。
任何时候我们均可增加或减少观察者,而不必改变主题的代码,因为主题只依赖与观察者接口;相反,更改主题
代码时,而不会影响到观察者,因为观察者只依赖于主题接口的方法;所以只要他们均遵守接口约定,我们就可
以自由的改变他们;
2、针对接口编程,不针对实现编程 主题和观察者均使用接口,观察者利用主题接口方法注册对象,主题利用观察者接口方法通知观察者,这样两者 之间即可相互协作运行,也同时具备松耦合的有点;
3、多用组合,少用继承 观察者模式利用”组合”将许多观察者组合进主题中。对象之间不是通过继承产生这种关系,而是通过运行时利用 组合发方式而产生的;
4、封装变化 观察者模式中变化的是主题的状态,以及观察者的数目和类型,利用这个模式,可以改变依赖主题状态的对象,而 不必更改主题;
4、 优缺点和适用场景
优点:
- 实现了表示层view和数据逻辑层mode相互分离,并定义了稳定的消息更新传递机制,抽象了更新接口,使得可 以有各种各样不同的表示层作为具体观察者角色。
- 主题和观察者直接建立了一个抽象的耦合;
- 符合开放,封闭原则;
缺点:
- 观察者太多,会消耗很多时间;
- 观察者和主题之间若存在循环依赖,会导致系统崩溃;
- 主题不知道观察者会发生什么变化,只知道发生了变化;
适用场景:
- 一个对象的改变会引起多个对象的变化,而不知道具体有多少个对象发生变化,可降级对象减的耦合度;
- 一个对象必须通知其他对象,而不知道这些对象是谁;
- 需要在系统中创建一个触发链,a触发b,b触发c,..
5、实例
例:气象监测,weatherData负责监测天气的气温,气压,温度等,每当监测到新的数据时,需要及时展示在多个展示
板上。
类图结构:
主题接口:
public interface Subject<T> {
void registerObserver(Observer observer);
void removeObserver(Observer observer);
void notifyObserver(T t);
}
天气预报实现类:
public class WeatherData implements Subject<Weather> {
List<Observer> observerList = new ArrayList<Observer>();
public void registerObserver(Observer observer) {
observerList.add(observer);
}
public void removeObserver(Observer observer) {
int index = observerList.indexOf(observer);
if (index >= 0) {
observerList.remove(index);
}
}
public void notifyObserver(Weather weather) {
for(Observer observer : observerList) {
observer.updata(weather);
}
}
public void measurementChange() {
Weather weather = new Weather(12, 13, 14);
notifyObserver(weather);
}
}
观察者接口:
public interface Observer<T> {
void updata(T t);
}
具体展示模板:
public class SecondDisplay implements Observer<Weather> {
private Subject subject;
public SecondDisplay(Subject subject) {
this.subject = subject;
subject.registerObserver(this);
}
public void updata(Weather weather) {
System.out.println(this.getClass() + "输出天气预报:" + weather.toString());
}
}
public class StaticsDisplay implements Observer<Weather> {
private Subject subject;
public StaticsDisplay(Subject subject) {
this.subject = subject;
subject.registerObserver(this);
}
public void updata(Weather weather) {
System.out.println(this.getClass() + "输出天气预报:" + weather.toString());
}
}
测试类:
public class Test {
public static void main(String[] args) {
WeatherData weatherData = new WeatherData();
// 实现并注册观察者
new SecondDisplay(weatherData);
new StaticsDisplay(weatherData);
weatherData.measurementChange();
}
}