文章目录
观察者模式(Observer Pattern)
**观察者模式(Observer Pattern)**属于行为型模式。
【观察者模式与**发布-订阅模式(Publish/Subscribe)**有一定区别。在发布-订阅模式里,发布者并不会直接通知订阅者,而且互不相关,他们关联则是依靠第三者进行通信(如消息中间件)。】
什么是观察者模式?
Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.
定义对象之间的一对多依赖关系,以便在一个对象更改状态时,自动通知和更新其所有依赖项。
UML
角色
- **主题(Subject):**主题是一个接口,该接口规定了与观察者相关的方法以及根据实际情况的其他方法,比如,添加、删除观察者以及通知观察者更新数据的方法。主题拥有一个集合,存放观察者。
- **具体主题(ConcreteSubject):**具体主题是实现主题接口类的一个实例,该实例包含其具体业务。使用抽象主题类中的方法通知观察者。
- **抽象观察者(Observer):**观察者是一个接口,该接口规定了具体观察者用来更新数据的方法。
- **具体观察者(ConcreteObserver):**具体观察者是实现观察者接口类的一个实例。增加到主题变量中,即可在主题变化时更新数据。可以根据实际情况来保存具体主题的引用,来进行相关的数据更新操作。
应用
使用模板(手写)
类Subject
:主题(被观察者对象)。
此处为简要代码,将主题与具体主题进行了合并,并且直接触发观察者。
将主题与具体主题区分后,主题中主要封装的就是关于观察者的方法。而具体主题中是主题自己的逻辑,通过调用父类中方法来触发观察者放法。
public class Subject {
//在被保存的类中保存观察者对象列表
private List<Observer> observers = new ArrayList<>();
//添加观察者类
public void addObserver(Observer observer) {
observers.add(observer);
}
//删除观察者类
public void removeObserver(Observer observer) {
observers.remove(observer);
}
//通知所有观察者,并执行对应的方法
public void notifyObservers() {
for (Observer observer : observers) {
observer.update();
}
}
}
类Observer
:抽象观察者
public abstract class Observer {
//其中保存了被观察的对象
protected Subject subject;
//被观察者变化时需要被触发的方法
public abstract void update();
}
类ConcreteObserver
:具体观察者
public class ConcreteObserverA extends Observer{
//将观察者与被观察者关联
public ConcreteObserverA(Subject subject){
//将被观察者对象放入当前对象
this.subject = subject;
//将当前对象放入被观察者对象的观察者列表中
this.subject.addObserver(this);
}
//观察者需要触发的方法的实现
@Override
public void update() {
System.out.println( "具体观察者A已经适配对象" + subject.toString() + "变动");
}
}
客户端
public class ObserverPattern {
public static void main(String[] args) {
//创建一个被观察者类
Subject subject = new Subject();
//使用被观察者创建观察者对象
Observer a = new ConcreteObserverA(subject);
Observer b = new ConcreteObserverB(subject);
Observer c = new ConcreteObserverC(subject);
//触发观察者
subject.notifyObservers();
System.out.println("------------------");
//删除观察者并触发
subject.removeObserver(a);
subject.notifyObservers();
}
}
控制台打印结果:
具体观察者A已经适配对象designPattern.observerPattern.Subject@63e31ee变动
具体观察者B已经适配对象designPattern.observerPattern.Subject@63e31ee变动
具体观察者C已经适配对象designPattern.observerPattern.Subject@63e31ee变动
------------------
具体观察者B已经适配对象designPattern.observerPattern.Subject@63e31ee变动
具体观察者C已经适配对象designPattern.observerPattern.Subject@63e31ee变动
使用模板(JDK)
java.util包中提供了Observable类和Observer接口
-
被观察者继承Observable类
-
观察则实现Observer接口
public class JDKObserver { public static void main(String[] args) { ConcreteSubject subject = new ConcreteSubject(); new ConcreteObserver(subject); subject.setStatus(1); } } class ConcreteSubject extends Observable { private Integer status; public Integer getStatus() { return status; } public void setStatus(Integer status) { if (!Objects.equals(status, this.status)) { this.status = status; System.out.println("被观察者:状态更改为" + status); setChanged(); } notifyObservers(); } } class ConcreteObserver implements Observer { private final ConcreteSubject subject; public ConcreteObserver(ConcreteSubject subject) { this.subject = subject; this.subject.addObserver(this); } // @Override // public void update(Observable o, Object arg) { // if (o instanceof ConcreteSubject) { // System.out.println("被观察者状态更改为:" + ((ConcreteSubject) o).getStatus()); // } // } @Override public void update(Observable o, Object arg) { if (o instanceof ConcreteSubject){ System.out.println("被观察者状态更改为:"+subject.getStatus()); } } }
-
缺点
- 扩展性不高。
Observable
是一个类,而不是一个接口。 - 只能使用继承才能使用完整的功能。
Observable
某些方法使用了protect
修饰,如果不继承自Observable
而是使用组合的方法,将有关键的方法不能调用。
- 扩展性不高。
为什么要使用观察者模式?
- 松耦合。由观察者自己决定是否进行监听操作。
- 可复用性。增加监听时主题以及监听的可复用性,低耦合的监听操作。
- 一对多。在一个对象进行改变时,想要不确定数量的对象随着该对象的改变而改变。
怎样使用观察者模式?
- 用被观察的类管理他的观察者(根据需要观察者中可以保存对应的被观察者)。
优缺点
优点
- 观察者与被观察者通过抽象类进行低耦合。
- 观察者无需主动去观察被观察对象的变化,而由被观察者主动去调用观察者的方法。
缺点
- 级联的观察链。当主题类也是另一个主题的观察类,那么会形成一个链状传播逻辑,造成代码的复杂性。
- 因为观察类而影响主业务(主题)的运行效率。因为在主业务触发所有观察类的方法时可能会因为某个或者过多的观察类导致效率较慢的问题。可以使用异步防止因为观察类相关的某处,出现问题而导致主业务效率受到影响。
应用解析
Spring中监听器,类org.springframework.context.ApplicationListener
。
@FunctionalInterface
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
/**
* Handle an application event.
* @param event the event to respond to
*/
//该方法类似于示例中的update方法
void onApplicationEvent(E event);
}