先来看一个场景
在很多业务中都存在一个流程类型的业务。比如一个在线商城系统下单操作,可能包含有以下几个流程:
- 检查库存
- 扣减库存
- 生成订单
- 通知用户
- 通知商家
简单的实现方法
最直接和简单的方法,就是根据现在业务的需要,我们在下单的这个操作中去调用库存检查、库存剪口、订单生成、用户通知、商家通知等API。然后搞定。
存在的问题
这种方法的问题在于,如果我们需要在某个流程中添加一个新的操作, 比如在扣减库存之后,我们需要添加一个操作,就是将库存扣减的结果写入到一个日志文件中。 那么我们就需要修改下单的这个操作,将这个操作加入到下单的操作中。 这样就会导致下单的这个操作变得越来越复杂,不利于维护。 这样的代码会变得难以维护,也不利于扩展。如何解耦这些流程与下单的操作,更好的方便拥抱变化呢?观察者模式就可以解决这么一个问题。
解决方式
我们可以采用观察者模式来解决这个问题。观察者模式的定义如下: 观察者模式(Observer Pattern):又可以称为订阅-发布模式,定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。 在上述的场景中,我们可以将下单操作作为一个主题,库存检查、库存扣减、订单生成、用户通知、商家通知等操作作为观察者。当下单操作发生时,所有的观察者都会收到通知,然后执行自己的操作。 这样当需要增加或者移除流程时,就不需要修改下单操作,只需要增加或者移除观察者的列表即可。可以很方便地解决需求的变化。
观察者模式类图表示
classDiagram
Subject <|-- ConcreteSubject
Observer "1" *-- "*" Subject : observes
Observer <|-- ConcreteObserver
ConcreteSubject "1" *-- "*" ConcreteObserver : notifies
class Subject{
+attach(observer:Observer)
+detach(observer:Observer)
+notify()
}
class ConcreteSubject{
+state:string
+getState():string
+setState(state:string)
}
class Observer{
+update(subject:Subject)
}
class ConcreteObserver{
+observerState:string
+update(subject:Subject)
}
简单的理解
- 观察者继承观察者接口,实现update方法。
- 被观察者继承被观察者接口,实现attach、detach、notify方法。
- 被观察者持有观察者的列表,当被观察者发生变化时,会通知所有的观察者。
- 被观察者的变化会触发观察者的update方法,观察者可以根据自己的需求来实现update方法。
代码实现
观察者接口
//观察者接口
public interface Observer {
void update(Subject subject);
}
//被观察者接口
public interface Subject {
void attach(Observer observer);
void detach(Observer observer);
void notifyObservers();
}
public class OrderService implements Subject {
private List<Observer> observers = new ArrayList<>();
public void attach(Observer observer) {
observers.add(observer);
}
public void detach(Observer observer) {
observers.remove(observer);
}
public void notifyObservers() {
for (Observer observer : observers) {
observer.update(this);
}
}
public void createOrder() {
System.out.println("创建订单");
notifyObservers();
}
}
public class ObserverOne implements Observer {
public void update(Subject subject) {
System.out.println("观察者收到通知,执行自己的操作");
}
}
public class ObserverTest {
public static void main(String[] args) {
OrderService orderService = new OrderService();
ObserverOne observerOne = new ObserverOne();
orderService.attach(observerOne);
orderService.createOrder();
}
}
优缺点
优点
- 观察者和被观察者之间是抽象耦合的。
- 建立一套触发机制。
- 观察者模式支持广播通信。
- 观察者模式符合“开闭原则”。
缺点
- 如果一个被观察者有很多直接和间接的观察者时,将所有的观察者都通知到会花费很多时间。
- 如果在观察者和被观察者之间有循环依赖,观察者会等待被观察者处理完再处理,将导致系统崩溃。
- 观察者之间有过多的细节依赖,提高时间消耗及程序复杂度。
应用场景
- 关联行为场景。需要注意的是,关联行为是可拆分的,而不是“组合”关系。
- 事件多级触发场景。
- 跨系统的消息交换场景,如消息队列的处理机制。