一、定义
定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会受到通知并自动更新。
例如:报纸订阅服务,出版者和订阅者。
二、角色
1、Subject,主题接口,对象使用此接口注册为观察者,或者把自己从观察者中删除。
2、Observer,观察者接口,一个主题可以有多个观察者。所有潜在的观察者必须实现观察者接口,这个接口只有update()一个方法,当主题发生改变时它被调用。
3、ConcreteObserver,具体的观察者,可以是实现观察者接口的任意类。观察者必须注册具体主题,以便接收更新。
4、ConcreteSubject,一个具体主题总是实现主题接口,除了注册和撤销方法之外,具体主题还实现了notifyObserver()方法,此方法用于在状态改变时更新所有当前观察者。具体主题也可能有设置和获取状态的方法。
三、松耦合的威力
当两个对象之间松耦合,它们依旧可以交互,但是不太清楚彼此的细节。
观察者模式提供了一种对象设计,让主题和观察者之间松耦合。
松耦合的设计之所以能让我们建立有弹性的OO系统,能够应对变化,是因为对象之间的相互依赖降到了最低。
四、注意点
1、观察者可以观察多个目标,但是更新方法需要实现多个,一个更新方法对应一个目标。避免业务混淆。
2、一个目标可以有多个观察者,通过遍历观察者进行通知。
3、观察者依赖于目标对象,注册时需要将观察者对象引用添加至目标对象的属性中。
4、设置值可以先判断是否更新了值,再去更新状态,然后确定是否设置值和调用方法。
5、可以将目标注入至Spring的IOC容器中,再在Spring中注入一个注册管理类,进行观察者的注册管理。再bean初始化时,将观察者注入至目标对象中。
6、多个观察者模型对象中不能有执行顺序依赖。
7、拉模型,update更新方法中传递目标实现对象。推模型,update更新方法中只传递需要的数据信息。一般使用拉模型,方便获取目标对象的所有数据,易于业务扩展。
五、命名建议(发布订阅模式)
1、目标接口的定义,建议在名称后面跟subject;
2、观察者接口的定义,建议在名称后面跟observer;
3、观察者接口的更新方法,建议名称为update。
4、实现类前面建议加,concrete。
六、观察者模式的调用顺序示意图
1、维护接口,创建目标对象,创建观察者对象,向目标对象注册观察者对象。
2、运行接口,改变目标对象的状态,通知所有注册的观察者对象进行相应的处理,回调目标对象,获取相应的数据。
七、思路笔记
1、创建主题接口,提供三个方法(添加方法、删除方法、通知方法),一个集合属性(订阅者的接口引用集合)。
2、主题接口实现类,实现主题接口的类便是需要保存值的对象模型,其中进行数据通知的具体方法操作,当这个类中的属性参数变化时,便出发notify方法。
3、notify方法中,遍历订阅者接口引用对象,使用订阅者对象调用update更新方法,可传入主题接口实现类对象,拉模型方式。
4、拉模型方式中,订阅者可以根据自身需要,获取主题接口实现类中的数据信息,进行业务操作。
5、创建观察者接口,观察者接口只提供一个公共的更新方法,update(),参数可以是主题接口实现类对象。
6、观察者接口实现类,实现update(),在其中根据获取主题接口实现类中的状态参数值进行业务实现操作。
优点
1、观察者与目标解耦。
2、实现了动态联动,只需要添加注册观察者即可。
3、支持广播通信
缺点
1、每个都需要调用update,可能引起不必要的性能消耗。
八、示例代码块
1、观察者注册管理器
package com.fly.simpletools.service.observer;
import com.fly.simpletools.service.observer.observer.ConcreteOneObserver;
import com.fly.simpletools.service.observer.observer.ConcreteTwoObserver;
import com.fly.simpletools.service.observer.subject.Subject;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
/**
* @author Mr_Fei
* @description 观察者注册器
* @date 2020-07-19 16:16
*/
@Component
public class RegisterObserverHandler {
@Resource
private Subject subject;
@Bean
private void register() {
//注册观察者1
subject.addObserver(new ConcreteOneObserver());
//注册观察者2
subject.addObserver(new ConcreteTwoObserver());
}
}
2、主题接口
package com.fly.simpletools.service.observer.subject;
import com.fly.simpletools.service.observer.observer.Observer;
/**
* @author Mr_Fei
* @description 自己实现的主题接口
* @date 2020-07-19 16:18
*/
public interface Subject {
/**
* @param observer 观察者
* @author Mr_Fei
* @date 2020/7/19 16:35
* @description 注册观察者接口
*/
void addObserver(Observer observer);
/**
* @param observer 观察者
* @author Mr_Fei
* @date 2020/7/19 16:35
* @description 移除观察者
*/
void deleteObserver(Observer observer);
/**
* @author Mr_Fei
* @date 2020/7/19 16:35
* @description 通知观察者
*/
void notifyObserver();
/**
* @author Mr_Fei
* @date 2020/7/19 16:35
* @description 设置改变状态
*/
void setChanged();
}
3、主题实现类
package com.fly.simpletools.service.observer.subject;
import com.fly.simpletools.service.observer.observer.Observer;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
/**
* @author Mr_Fei
* @description 主题实现类
* @date 2020-07-19 16:22
*/
@Component
public class ConcreteSubject implements Subject {
/**
* 传递通知内容
*/
private Object content;
/**
* 存放观察者的集合
*/
private List<Observer> observers = new ArrayList<>();
/**
* 判断是否内容发生变化
*/
private boolean changed = false;
@Override
public void addObserver(Observer observer) {
if (observer != null) {
this.observers.add(observer);
}
}
@Override
public void deleteObserver(Observer observer) {
if (observer != null) {
this.observers.remove(observer);
}
}
@Override
public void notifyObserver() {
if (observers.isEmpty() || !changed) {
return;
}
for (Observer observer : observers) {
observer.update(this, content);
}
this.changed = false;
}
@Override
public void setChanged() {
this.changed = true;
}
public Object getContent() {
return content;
}
/**
* @param content 内容
* @author Mr_Fei
* @date 2020/7/19 16:36
* @description set方法判断值是否发生改变,改变则通知观察者
*/
public void setContent(Object content) {
if (content != this.content) {
this.setChanged();
}
this.content = content;
this.notifyObserver();
}
}
4、观察者接口
package com.fly.simpletools.service.observer.observer;
import com.fly.simpletools.service.observer.subject.Subject;
/**
* @author Mr_Fei
* @description 观察者接口
* @date 2020-07-19 16:19
*/
public interface Observer {
/**
* @param subject 主题对象,拉方式参数
* @param arg 消息内容,推方式参数
* @author Mr_Fei
* @date 2020/7/19 16:20
* @description 更新方法
*/
void update(Subject subject, Object arg);
}
5、观察者实现1
package com.fly.simpletools.service.observer.observer;
import com.fly.simpletools.service.observer.subject.Subject;
import com.fly.simpletools.service.observer.subject.ConcreteSubject;
/**
* @author Mr_Fei
* @description 观察者1
* @date 2020-07-19 16:26
*/
public class ConcreteOneObserver implements Observer {
@Override
public void update(Subject subject, Object arg) {
ConcreteSubject testSubject = (ConcreteSubject) subject;
//进行业务操作
System.out.println("TestOneObserverImpl收到主题通知消息内容:" + testSubject.getContent());
}
}
6、观察者实现2
package com.fly.simpletools.service.observer.observer;
import com.fly.simpletools.service.observer.subject.Subject;
import com.fly.simpletools.service.observer.subject.ConcreteSubject;
/**
* @author Mr_Fei
* @description 观察者2
* @date 2020-07-19 16:26
*/
public class ConcreteTwoObserver implements Observer {
@Override
public void update(Subject subject, Object arg) {
ConcreteSubject testSubject = (ConcreteSubject) subject;
//进行业务操作
System.out.println("TestTwoObserverImpl收到主题通知消息内容:" + testSubject.getContent());
}
}