设计模式-观察者模式 (在spring下的使用)

目录

1. 简介 

2.示例

3.在sping的应用可更为简单 采用继承事件ApplicationEvent

4.相关说明

5.项目中的应用


1. 简介 

      观察者模式( Observer Design Pattern )也被称为发布订阅模式( Publish-Subscribe Design Pattern )。它的定义是这样的  在对象之间定义⼀个⼀对多的依赖,当⼀个对象状态改变的时候,所有依赖的对象都会⾃动收到 通知
      ⼀般情况下,被依赖的对象叫作被观察者( Observable ),依赖的对象叫作观察者( Observer )。不过,在实际的项⽬开发中,这两种对象的称呼是⽐较灵活的,有各种不同的叫法,⽐如:Subject-Observer Publisher Subscriber、 Producer-Consumer EventEmitter-EventListener Dispatcher-Listener。不管怎么称呼,只要应⽤场景符合刚刚给出的定义,都可以看作观察者模式。

观察者模式作为行为型设计模式,主要也是为了不同的业务行为的代码 解耦。
优点
  • 松散耦合:观察者模式实现了发布-订阅机制,主题对象和观察者对象之间是松散耦合的,它们不需要了解彼此的细节。
  • 可扩展性:可以随时添加或删除观察者,而不会影响其他部分的代码。
  • 可重用性:主题对象和观察者对象可以在不同的场景中重复使用,减少了代码重复。
缺点
  • 如果观察者较多的情况下,可能会导致整体的业务逻辑变得不够清晰。
  • 默认情况下消息的通知及处理是顺序同步的,一个观察者的卡顿会影响整体的执行效率。当然可以 设计成异步,但顺序就没办法保证了。
  • 因为观察者与被观察者之间是完全解耦合的,所无法保证观察者是否做出正确的应对措施。 也就是说通知发出去之后是没办法保证观察者正常执行了对应的代码逻辑,因为这中途可能因为某 些原因报错,导致执行失败 所以我们在设计之初就得先确认是否能够容忍这种情况发生,如果不能那策略模式可能就不适合 当然,也可以增加应答机制来保证,比如kafka之类的消息队列框架,就是通过应答机制来确保消息 得到正确的消费,但同时也会带来吞吐效率下降的问题 所以我们在实际应用当中还是需要根据具体的业务以及需求情况来确定使用何种设计模式

2.示例

Subject(主题): 主要由类实现的可观察的接口,通知观察者使用attach方法,以及取消观察的detach方法。
ConcreteSubject(具体主题): 是一个实现主题接口的类,处理观察者的变化
Observe(观察者): 观察者是一个由对象实现的接口,根据主题中的更改而进行更新。

设计模式-观察者模式 (在spring下的使用)_第1张图片
public interface Subject {
 void registerObserver(Observer observer);
 void removeObserver(Observer observer);
 void notifyObservers(Message message);
}
public interface Observer {
 void update(Message message);
}
public class ConcreteSubject implements Subject {
 private List observers = new ArrayList();
 @Override
 public void registerObserver(Observer observer) {
 observers.add(observer);
 }
 @Override
 public void removeObserver(Observer observer) {
 observers.remove(observer);
 }
 @Override
 public void notifyObservers(Message message) {
 for (Observer observer : observers) {
 observer.update(message);
 }
 }
}
public class ConcreteObserverOne implements Observer {
 @Override
 public void update(Message message) {
 //TODO: 获取消息通知,执⾏⾃⼰的逻辑...
 System.out.println("ConcreteObserverOne is notified.");
 }
}
public class ConcreteObserverTwo implements Observer {
 @Override
 public void update(Message message) {
 //TODO: 获取消息通知,执⾏⾃⼰的逻辑...
 System.out.println("ConcreteObserverTwo is notified.");
 }
}
public class Demo {
 public static void main(String[] args) {
 ConcreteSubject subject = new ConcreteSubject();
 subject.registerObserver(new ConcreteObserverOne());
 subject.registerObserver(new ConcreteObserverTwo());
 subject.notifyObservers(new Message());
 }
}

3.在sping的应用可更为简单 采用继承事件ApplicationEvent

1.定义事件并继承ApplicationEvent

public class CaseOperationRecordEvent extends ApplicationEvent {
  public CaseOperationRecordEvent(Map source) {
    super(source);
  }
}

2.将新事件加入sping容器管理

@Component
@Data
@EnableSpringUtil
public class CaseOperationRecordPublisher {
  public static void publishEvent(Map source) {
    SpringUtil.getApplicationContext().publishEvent(new CaseOperationRecordEvent(source));
  }
}

3.定义监听类 实现相关业务代码

@Component
@Slf4j
public class CaseOperationRecordListener {
  
  @Async
  @Order
  @EventListener(CaseOperationRecordEvent.class)
  public void saveCaseOperationRecord(CaseOperationRecordEvent event) {
    Map source = (Map) event.getSource();
    //业务代码
  }
}

4.实现调用

  public static void main(String[] args) {
    CaseOperationRecordPublisher.publishEvent(source);
  }

4.相关说明

@EventListener  将一个方法标记为监听器,用于监听应用程序事件,事件可以是 ApplicationEvent实例,也可以是其他任意的对象,对 @EventListener 注解的处理是通过内部的EventListenerMethodProcessor Bean进行的,当使用Java配置时,它被自动注册,当使用XML配置时,则通过context:annotation-config/或context:component-scan/元素手动注册


@Async  

当需要异步处理监听器时,可以在监听器方法上再增加另外的一个Spring注解 @Async,但需要注意以下限制:

1.监听器报错不会传递给事件发起者,因为双方已经不在同一个线程了。
2. 异步监听器的非空返回值不会被当作新的事件发布。如果需要发布新事件,需要注入 ApplicationEventPublisher后手动发布
同步监听器抛出的所有checked异常都会被封装成 UndeclaredThrowableException。

@Order

如果同一个事件可能会被多个监听器监听处理,那么我们可以使用 @Order 注解对各个监听器进行排序。order的值越小,优先级越高,如果不标注数字,默认最低优先级

5.项目中的应用

在博主的项目中的应用则为一些行为日志的保存,AOP 对于可以从请求参数就可获取全部日志内容的情况,通过切面统一处理,
策略模式:对于不能直接从请求参数里面获取的日志内容的情况,通过不同策略实现类处理;
观察者:针对日志需要不存到不同类型数据库,
              或日志内容在切面里面获取相对麻烦,
              或日志内容获取比较耗时且已经在具体业务方法里面已经查询出来的情况;

        其实观察者模式相当于一个单机的Mq,对于其适用性需具体分析。在选择设计模式之前,首先要深刻理解你的问题领域和需求。不要为了使用设计模式而使用它们。

你可能感兴趣的:(设计模式,设计模式,观察者模式)