概述
设计模式之—观察者模式(Observer Pattern)
一. 定义及应用范围
在对象之间定义了一对多的依赖,这样一来,一个对象的状态改变了,依赖它的对象会收到通知并自动更新。其实就是发布订阅模式,发布者发布消息,订阅者订阅消息。订阅了就能收到消息,没订阅就收不到消息。
观察者模式还有其他的一些称谓,比如: 发布-订阅模式,模型-视图模式,源-监听器模式,从属模式。其实都是说的是一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个对象在状态发生变化时,会通知所有观察者对象,使它们自动的更新自己。
二. 优缺点
- 优点:
- 主题和观察者之间建立了一个抽象的偶尔,而非紧密的偶尔,降低了代码的耦合度
- 支持广播通信,主题会向所有注册了的观察者发送通知,简化了系统一对多的设计难度;
- 符合开闭原则,增加新的观察者无需修改原有代码,代码的可扩展性高。
- 缺点
- 如果主题有很多的直接或间接的观察者,那么全部通知到所有的观察者会很耗时。
- 主题和观察者之间如果存在循环依赖,可能导致系统崩溃。
三. 角色划分
-
Subject被观察者
定义被观察者必须实行的职责,必须具有动态的增加、删除观察者。它一般是抽象类或实现类,仅仅是完成被观察者必须实现的职责: 管理观察者并通知观察者。
-
Observer观察者
观察者接收到消息后,进行update更新操作,对接收到的信息进行处理。
-
ConcreteSubject具体的被观察者
定义被观察者的具体业务逻辑,同时定义哪些事件进行通知
-
ConcreteObserver具体的观察者
每个观察者接收到信息后的处理反应是不同的,各个观察者有各自的处理逻辑。
-
具体的类图结构:
四. 代码实现
-
Suject被观察者接口
public interface Subject { void add(Observer observer); void remove(Observer observer); void notifyObserver(); }
-
Observer观察者
public interface Observer<T> { void update(T t); }
-
ConcreteSubject具体的被观察者
public class OrderSuject implements Subject { private List<Observer> observerList = Collections.synchronizedList(new ArrayList<>()); private String message; public OrderSuject(String message) { this.message = message; } @Override public void add(Observer observer) { observerList.add(observer); } @Override public void remove(Observer observer) { observerList.remove(observer); } @Override public void notifyObserver() { observerList.forEach(observer -> observer.update(message)); } }
-
ConcreteObserver具体的观察者
public class SmsObserver implements Observer<String>{ @Override public void update(String s) { System.out.println("发送短信:"+s); } }
public class EmailObserver implements Observer<String>{ @Override public void update(String s) { System.out.println("发送短信:"+s); } }
-
测试类
public class ObserverTest { public static void main(String[] args) { OrderSuject orderSuject=new OrderSuject("订单创建成功了"); orderSuject.add(new SmsObserver()); orderSuject.add(new EmailObserver()); orderSuject.notifyObserver(); } } //运行结果为: //发送短信:订单创建成功了 //发送短信:订单创建成功了
五. 基于JDK实现的观察者模式
jdk内置了观察者接口java.util.Observer,主题被观察者 java.util.Observable。观察者实现Observer接口,被观察者继承Observable类。
-
观察者
public class SmsObserver implements Observer { @Override public void update(Observable o, Object arg) { System.out.println("jdk用户下单成功,准备发送短信了:"+arg.toString()); } }
public class EmailObserver implements Observer { @Override public void update(Observable o, Object arg) { System.out.println("jdk用户下单成功,准备发送邮件了:"+arg.toString()); } }
-
被观察者
public class OrderObservable extends Observable { @Override public void notifyObservers(Object arg) { setChanged(); super.notifyObservers(arg); } public static void main(String[] args) { OrderObservable orderObservable=new OrderObservable(); orderObservable.addObserver(new EmailObserver()); orderObservable.addObserver(new SmsObserver()); orderObservable.notifyObservers("订单创建成功"); } } //运行结果: //jdk用户下单成功,准备发送短信了:订单创建成功 //jdk用户下单成功,准备发送邮件了:订单创建成功
六. Spring事件监听机制
Spring的事件监听机制其实就是基于观察者模式来实现的。Spring实现监听机制有多种方式,具体如下:
1. Spring实现观察模式之方式一
-
监听事件: 实现ApplicationEvent 抽象类
-
监听者/观察者: 实现ApplicationListener接口,重写onApplicationEvent方法
-
发布事件: 通过 ApplicationEventPublisher接口的publishEvent方法发布事件 ,ApplicationContext继承了ApplicationEventPublisher接口。
-
具体代码实现如下:
//订单事件类 @Getter @Setter public class OrderEvent extends ApplicationEvent { private Order order; public OrderEvent(Object source,Order order) { super(source); this.order=order; } }
//短信监听类,监听事件OrderEvent @Component public class SmsListener implements ApplicationListener<OrderEvent> { @Override public void onApplicationEvent(OrderEvent event) { Order order = Optional.ofNullable(event.getOrder()).orElseGet(Order::new); System.out.println("订单创建成功了,准备发送短信了:"+order.getCode()); } }
// 邮件监听类,监听事件OrderEvent @Component public class EmailListener implements ApplicationListener<OrderEvent> { @Override public void onApplicationEvent(OrderEvent event) { Order order = Optional.ofNullable(event.getOrder()).orElseGet(Order::new); System.out.println("订单创建成功了,准备发送邮件了,cod:"+order.getCode()); } }
@RunWith(SpringRunner.class) @SpringBootTest(classes = ApiServerApplication.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) public class ApiServerApplicationTest { @Autowired private ApplicationContext applicationContext; @Test public void testEvent(){ Order order=new Order(); order.setId(15L); order.setCode("X15212541"); OrderEvent orderEvent = new OrderEvent(this, order); applicationContext.publishEvent(orderEvent); } } //输出结果: //订单创建成功了,准备发送邮件了,cod:X15212541 //订单创建成功了,准备发送短信了:X15212541
2.Spring注解@EventListener实现监听
除了实现ApplicationListener接口之外,Spring可以通过注解@EventListener注解实现监听类,具体如下:
//通过注解@EventListener代替ApplicationListener实现事件监听
@Component
public class TelListener {
@EventListener
public void onApplicationEvent(OrderEvent event){
System.out.println("我是注解驱动监听类,订单创建成了,code="+event.getOrder().getCode());
}
}
// 运行结果:
//我是注解驱动监听类,订单创建成功了,code=X15212541
//订单创建成功了,准备发送邮件了,cod:X15212541
//订单创建成功了,准备发送短信了:X15212541
@EventListener注解还可以通过配置condition条件来设置满足特定条件后,才执行该监听事件,支持SpringEL表达式
3.异步执行监听事件
-
Spring支持同步和异步两种方式来执行监听事件,具体原理见 SimpleApplicationEventMulticaster类 :
如下代码可以看到,如果Executor 不为空就会采用异步方式执行,否则的话就是同步方式
@Override
public void multicastEvent(final ApplicationEvent event, ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
Executor executor = getTaskExecutor();
if (executor != null) {
executor.execute(new Runnable() {
@Override
public void run() {
invokeListener(listener, event);
}
});
}
else {
invokeListener(listener, event);
}
}
}
- 实现异步执行的方式
- 在SpringBoot启动类上配置上 开启@EnableAsync
- 在监听方法上加上注解@Async,开启异步执行。开启新的线程去执行这个监听任务,如下可见线程ID明显发生了变化,不是同一个线程执行的结果。
- 采用异步的方式是为了让主线程快速的结束,给用户进行响应,事件后台异步执行。
@Component
public class SmsListener implements ApplicationListener<OrderEvent> {
@Override
@Async
public void onApplicationEvent(OrderEvent event) {
Order order = Optional.ofNullable(event.getOrder()).orElseGet(Order::new);
System.out.println("线程ID="+Thread.currentThread().getId()+" | 订单创建成功了,准备发送短信了:"+order.getCode());
}
}
运行结果:
线程ID=1我是注解驱动监听类,订单创建成功了,code=X15212541
线程ID=1订单创建成功了,准备发送邮件了,cod:X15212541
线程ID=57 | 订单创建成功了,准备发送短信了:X15212541
4.事务事件 @TransactionalEventListener
Spring提供了@TransactionalEventListener注解,它是@EventListener的一个扩展。允许将事件的监听器绑定到事务的一个阶段。具体的事务阶段包含以下4个:
public enum TransactionPhase {
BEFORE_COMMIT (默认),
AFTER_COMMIT,
AFTER_ROLLBACK,
AFTER_COMPLETION
}
- BEFORE_COMMIT :在事务成功后触发该监听事件
- AFTER_COMMIT : 事务回滚时触发该监听事件
- AFTER_ROLLBACK : 事务完成后触发,不论是否成功
- AFTER_COMPLETION: 事务提交之前触发
需要注意的是,如果没有正在运行的事务,就不会触发该事件,除非设置fallbackExecution =true
@TransactionalEventListener(fallbackExecution = true)
最后
以上就是听话服饰为你收集整理的归纳之_观察者模式_详细总结设计模式之—观察者模式(Observer Pattern)的全部内容,希望文章能够帮你解决归纳之_观察者模式_详细总结设计模式之—观察者模式(Observer Pattern)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复