中介者模式 (Mediator Pattern)

好的,我们来深入探讨 中介者模式 (Mediator Pattern),并结合 多个事件通道(Event Channels)多个事件处理器(Event Processors) 的场景进行详细的讲解。

中介者模式的详细讲解

在更复杂的事件驱动架构中,系统中的各个组件可能涉及不同的事件流。每个事件通道 (Event Channel) 和事件处理器 (Event Processor) 可能负责处理不同种类的事件或不同的业务逻辑。通过引入中介者模式,可以有效地协调和解耦这些组件,确保它们之间的独立性和灵活性。

核心角色及其功能:
  1. 事件 (Event):表示系统中的某种行为或状态变化(例如:订单创建、用户登录)。
  2. 事件队列 (Event Queue):存储所有的事件,按序列管理,确保事件的顺序性。
  3. 事件通道 (Event Channel):负责将事件分发到相关的事件处理器。
  4. 事件中介者 (Event Mediator):负责接收事件,并决定将事件传递给哪些事件通道,最终由事件通道把事件传递给具体的事件处理器。
  5. 事件处理器 (Event Processor):负责具体处理事件的逻辑,如更新数据库、发送通知等。

架构流程

事件流的高级流程:
  1. 事件的产生:当用户提交订单时,产生了一个“订单创建事件”。
  2. 事件加入队列:事件被加入到 事件队列 中,等待被处理。
  3. 事件的路由:事件通过 事件中介者,它负责判断事件的类型,并将事件分发到合适的 事件通道
  4. 事件的处理:每个事件通道将事件分发到不同的 事件处理器,每个事件处理器根据事件的内容处理业务逻辑。
  5. 事件处理完毕:事件处理完毕后,相关的状态更新或其他后续操作会被执行。

复杂的多通道与多处理器模式

在复杂系统中,可能有多个事件通道,每个事件通道会根据事件类型将事件分发给不同的处理器。每个处理器负责处理特定类型的事件。

例如:

  • 订单相关事件通道:负责处理所有与订单相关的事件(订单创建、支付、发货等)。
  • 库存相关事件通道:处理库存变动、库存调整等事件。
  • 通知事件通道:处理发送通知、消息等任务。

这种设计使得每个事件处理器只专注于处理特定类型的事件,降低了各个组件之间的耦合度,同时提高了灵活性和可扩展性。


UML 事件处理流程图

为了清晰表达这一架构,我们将使用 UML 序列图 来展示一个复杂的事件驱动架构,涉及多个事件通道与事件处理器的情况。

User "Event Queue" "Event Mediator" "Event Channel (Order)" "Event Channel (Stock)" "Event Channel (Notify)" "Order Processor" "Stock Processor" "Notify Processor" Create Order Event Enqueue Event Route Order Event Route Stock Event Route Notify Event Process Order Event Process Stock Event Process Notify Event User "Event Queue" "Event Mediator" "Event Channel (Order)" "Event Channel (Stock)" "Event Channel (Notify)" "Order Processor" "Stock Processor" "Notify Processor"
图中的角色解释
  1. Event Source(事件源): 触发事件的源,如用户点击按钮、订单创建等。
  2. Event Queue(事件队列): 存储待处理的事件,确保事件有序、及时地被处理。
  3. Event Mediator(事件中介者): 作为中心化的控制器,决定事件需要被哪个通道处理。
  4. Event Channel(事件通道): 根据事件的类型,将事件分发给不同的事件处理器。可以有多个通道(如订单通道、库存通道、通知通道)。
  5. Event Processor(事件处理器): 具体负责处理事件的业务逻辑。

Java 代码实现

假设我们有一个电商系统,在系统中,当订单创建时,事件会通过不同的事件通道进行分发和处理。每个事件通道都会分发事件到特定的处理器。

代码示例
// 事件类
public class OrderEvent {private String orderId;private String eventType;public OrderEvent(String orderId, String eventType) {this.orderId = orderId;this.eventType = eventType;}public String getOrderId() {return orderId;}public String getEventType() {return eventType;}
}// 事件队列
import java.util.LinkedList;
import java.util.Queue;public class EventQueue {private Queue<OrderEvent> eventQueue = new LinkedList<>();public void enqueue(OrderEvent event) {eventQueue.add(event);}public OrderEvent dequeue() {return eventQueue.poll();}
}// 事件中介者
public class EventMediator {private EventQueue eventQueue;private EventChannel orderChannel;private EventChannel stockChannel;private EventChannel notifyChannel;public EventMediator(EventQueue eventQueue, EventChannel orderChannel, EventChannel stockChannel, EventChannel notifyChannel) {this.eventQueue = eventQueue;this.orderChannel = orderChannel;this.stockChannel = stockChannel;this.notifyChannel = notifyChannel;}public void processEvents() {OrderEvent event = eventQueue.dequeue();if (event != null) {// 根据事件类型,路由到不同的事件通道if ("OrderCreated".equals(event.getEventType())) {orderChannel.routeEvent(event);} else if ("StockUpdate".equals(event.getEventType())) {stockChannel.routeEvent(event);} else if ("Notification".equals(event.getEventType())) {notifyChannel.routeEvent(event);}}}
}// 事件通道
public class EventChannel {private EventProcessor processor;public EventChannel(EventProcessor processor) {this.processor = processor;}public void routeEvent(OrderEvent event) {processor.processEvent(event);}
}// 事件处理器
public class EventProcessor {private String processorName;public EventProcessor(String processorName) {this.processorName = processorName;}public void processEvent(OrderEvent event) {System.out.println("Processor " + processorName + " is handling event for Order ID: " + event.getOrderId());// 具体的事件处理逻辑,如更新数据库、发送通知等}
}// 使用示例
public class Main {public static void main(String[] args) {// 创建事件队列EventQueue eventQueue = new EventQueue();// 创建事件通道和事件处理器EventProcessor orderProcessor = new EventProcessor("Order Processor");EventProcessor stockProcessor = new EventProcessor("Stock Processor");EventProcessor notifyProcessor = new EventProcessor("Notify Processor");EventChannel orderChannel = new EventChannel(orderProcessor);EventChannel stockChannel = new EventChannel(stockProcessor);EventChannel notifyChannel = new EventChannel(notifyProcessor);// 创建事件中介者EventMediator mediator = new EventMediator(eventQueue, orderChannel, stockChannel, notifyChannel);// 事件发生,订单创建OrderEvent orderCreatedEvent = new OrderEvent("12345", "OrderCreated");eventQueue.enqueue(orderCreatedEvent);// 事件中介者处理事件mediator.processEvents();}
}
代码解释
  1. OrderEvent:表示事件类,包含事件类型和订单ID。
  2. EventQueue:事件队列,用来缓存所有的事件。
  3. EventMediator:事件中

介者,负责从队列中取出事件并将其分发到对应的事件通道。
4. EventChannel:事件通道,负责将事件传递给具体的事件处理器。
5. EventProcessor:事件处理器,具体负责处理事件。

通过引入中介者模式,事件处理流程变得更加清晰,系统的解耦性也得到了提升。

结合DDD改造

项目结构与文件作用说明

以下是文件结构及每个文件的作用和使用场景,结合 领域驱动设计(DDD)事件驱动架构

src
├── com
│   └── example
│       ├── domain
│       │   ├── order
│       │   │   ├── OrderAggregate.java  <-- 处理与订单相关的业务逻辑
│       │   │   ├── OrderCreatedEvent.java  <-- 领域事件,表示订单创建的事件
│       │   ├── inventory
│       │   │   ├── InventoryAggregate.java  <-- 处理与库存相关的业务逻辑
│       ├── service
│       │   ├── OrderService.java  <-- 订单服务,调用 `OrderAggregate` 进行订单创建等业务逻辑
│       │   ├── InventoryService.java  <-- 库存服务,处理库存检查和库存更新
│       │   ├── NotificationService.java  <-- 发送通知的服务
│       ├── mediator
│       │   ├── EventMediator.java  <-- 事件中介者,负责监听和处理事件
│       ├── event
│       │   ├── Event.java  <-- 事件接口,定义事件的通用行为
│       │   ├── EventChannel.java  <-- 事件通道,用于发布和订阅事件
│       │   ├── EventProcessor.java  <-- 事件处理器接口,定义事件处理的规则
│       │   ├── EventQueue.java  <-- 事件队列,用于存储待处理的事件
│       └── notification
│           ├── NotificationService.java  <-- 发送通知的服务,实际发送业务相关的通知

文件说明与使用场景
1. OrderCreatedEvent.java:领域事件(Domain Event)
  • 作用:表示当订单创建时,系统需要发出的事件。领域事件是业务流程中的关键动作,用来触发其他的业务流程。
  • 场景:订单一旦创建,就需要通过事件来通知其他系统模块(如库存、通知服务等),以进行相应的业务操作。
public class OrderCreatedEvent {private String orderId;private LocalDateTime createdAt;public OrderCreatedEvent(String orderId) {this.orderId = orderId;this.createdAt = LocalDateTime.now();}public String getOrderId() {return orderId;}public LocalDateTime getCreatedAt() {return createdAt;}
}
2. OrderAggregate.java:聚合根(Aggregate Root)
  • 作用:处理与订单相关的核心业务逻辑。聚合根是一个业务模型,处理业务规则,确保状态的一致性。聚合根在 DDD 中的作用是统一管理领域对象,保证业务逻辑的完整性。
  • 场景:聚合根作为业务实体,处理订单的创建、状态更改等业务。
public class OrderAggregate {private String orderId;private String status;public OrderAggregate(String orderId) {this.orderId = orderId;this.status = "Created"; // 初始化订单状态}public void createOrder() {System.out.println("Order " + orderId + " has been created.");EventChannel.publish(new OrderCreatedEvent(orderId));  // 订单创建时发布事件}public String getStatus() {return status;}public String getOrderId() {return orderId;}
}
3. InventoryAggregate.java:库存聚合根(Inventory Aggregate)
  • 作用:处理与库存相关的业务逻辑。类似于 OrderAggregate,它是一个聚合根,负责管理库存的状态及库存操作。
  • 场景:当创建订单时,系统需要检查库存是否充足。如果库存充足,则减少库存量;否则提示缺货。
public class InventoryAggregate {private String productId;private int stockLevel;public InventoryAggregate(String productId) {this.productId = productId;this.stockLevel = 100; // 初始库存为100}public boolean checkStock() {return stockLevel > 0;}public void decreaseStock() {stockLevel--;}
}
4. OrderService.java:订单服务(Order Service)
  • 作用:订单服务协调 OrderAggregate 的操作,负责调用订单的创建方法。
  • 场景:用户提交订单时,服务会调用 OrderAggregate 创建订单,并触发相关的领域事件。
public class OrderService {public void createOrder(String orderId) {OrderAggregate orderAggregate = new OrderAggregate(orderId);orderAggregate.createOrder();  // 调用聚合根的方法,创建订单并发布事件}
}
5. InventoryService.java:库存服务(Inventory Service)
  • 作用:库存服务检查库存,若库存足够,则减少库存。
  • 场景:当订单创建后,库存服务需要检查相关商品的库存,并对库存进行减少操作。
public class InventoryService {public void checkInventory(String productId) {InventoryAggregate inventoryAggregate = new InventoryAggregate(productId);if (inventoryAggregate.checkStock()) {inventoryAggregate.decreaseStock();  // 库存充足,减少库存System.out.println("Inventory updated, stock level decreased.");} else {System.out.println("Out of stock.");}}
}
6. NotificationService.java:通知服务(Notification Service)
  • 作用:处理发送通知的业务逻辑,如通知用户订单创建成功。
  • 场景:订单创建后,通知服务会发送订单创建的通知给用户或相关系统。
public class NotificationService {public void sendNotification(String message) {System.out.println("Sending notification: " + message);  // 发送通知}
}
7. EventChannel.java:事件通道(Event Channel)
  • 作用:负责发布和订阅事件。它是一个简单的事件总线,用于解耦事件发布者和事件消费者。
  • 场景:当领域事件如 OrderCreatedEvent 被发布时,EventChannel 会负责将事件分发给适当的处理者(例如,库存服务、通知服务)。
public class EventChannel {private static final Map<String, EventProcessor> subscribers = new HashMap<>();public static void subscribe(String eventType, EventProcessor processor) {subscribers.put(eventType, processor);}public static void publish(Object event) {String eventType = event.getClass().getSimpleName();EventProcessor processor = subscribers.get(eventType);if (processor != null) {processor.process(event);  // 执行事件处理}}
}
8. EventProcessor.java:事件处理器接口(Event Processor)
  • 作用:定义了事件处理的接口,所有事件处理器都需要实现 process 方法。
  • 场景:每个事件处理器根据事件类型来处理业务逻辑。
public interface EventProcessor {void process(Object event);
}
9. EventMediator.java:事件中介者(Mediator)
  • 作用:监听和路由事件,协调不同模块间的通信,避免直接的依赖关系。
  • 场景EventMediator 监听事件(如 OrderCreatedEvent),当事件触发时,它协调其他服务(如库存服务和通知服务)进行相应处理。
public class EventMediator {private OrderService orderService = new OrderService();private InventoryService inventoryService = new InventoryService();private NotificationService notificationService = new NotificationService();public EventMediator() {EventChannel.subscribe("OrderCreatedEvent", this::onOrderCreated);}public void onOrderCreated(Object event) {if (event instanceof com.example.domain.order.OrderCreatedEvent) {com.example.domain.order.OrderCreatedEvent orderCreatedEvent = (com.example.domain.order.OrderCreatedEvent) event;inventoryService.checkInventory("product-id");  // 调用库存服务notificationService.sendNotification("Order " + orderCreatedEvent.getOrderId() + " created successfully.");}}
}
10. MainApp.java:主应用程序(Main Application)
  • 作用:模拟整个应用的启动,创建订单并触发事件。
  • 场景:用户提交订单后,MainApp 会通过 OrderService 创建订单,并触发事件到 EventMediator,完成业务流程。
public class MainApp {public static void main(String[] args) {EventMediator mediator = new EventMediator();// 模拟用户创建订单OrderService orderService = new OrderService();orderService.createOrder("order-123");}
}

总结

  • 每个文件的作用和场景都符合 领域驱动设计(DDD) 的原则,聚焦于业务

领域的实现与解耦。

  • 领域事件通过 EventChannel 发布,系统模块(如库存、通知)通过事件中介者 EventMediator 处理事件,实现业务逻辑的流转。
  • 该架构有效地将领域逻辑与基础设施(如事件发布与处理)解耦,便于系统扩展和维护。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/57260.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux之实战命令41:lshw应用实例(七十五)

简介&#xff1a; CSDN博客专家、《Android系统多媒体进阶实战》一书作者 新书发布&#xff1a;《Android系统多媒体进阶实战》&#x1f680; 优质专栏&#xff1a; Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a; 多媒体系统工程师系列【…

虚拟滚动是怎么做性能优化的?

前言 一个简单的情景模拟&#xff08;千万别被带入&#xff09;&#xff1a; A&#xff1a; 假设现在有 10 万条数据&#xff0c;你作为前端该怎么优化这种大数据的列表&#xff1f; B&#xff1a; 针对大数据列表一般不会依次性加载&#xff0c;会采用上拉加载、分页加载等…

如何用数据字典提升数据质量和决策效率?

在前面的文章中我们谈到过数据字典的概念&#xff0c;本文将继续探讨如何用数据字典提升数据质量和决策效率。 一、数据字典 数据字典&#xff1a;一种对数据的定义和描述的集合&#xff0c;它包含了数据的名称、类型、长度、取值范围、业务含义、数据来源等详细信息。 数据字…

Java中的一些名词概念

**函数式接口:** 概念&#xff1a;一个接口中的抽象方法只有一个&#xff0c;那么这个接口就是一个函数式接口。形参: 形参变量是**功能函数里的变量**&#xff0c;只有<u>在被调用的时候才分配内存单元</u>&#xff0c;<u>调用结束后立即释放</u>。…

AUTOSAR_EXP_ARAComAPI的6章笔记(2)

☞返回总目录 相关总结&#xff1a;AutoSar AP CM实例说明符的使用方法总结 6.2 实例说明符的使用方法 一、InstanceSpecifier 的概念 InstanceSpecifier 是在 [3] 中定义的一个核心概念&#xff0c;它由符合特定模型元素绝对路径的模型元素 shortName 组成&#xff0c;表现…

【10月最新】植物大战僵尸杂交版即将新增【植物】内容介绍预告(附最新版本下载链接)

新增植物 玉米旋转机 玉米旋转机是一种支持性植物&#xff0c;每4秒可散射6颗油炸玉米或黄油&#xff08;概率20%&#xff09;&#xff0c;油炸玉米经过火炬可变为爆米花&#xff0c;造成范围爆炸伤害。其价格为325&#xff0c;并在每种植一颗后&#xff0c;价格增加50。玉米旋…

Imagic: Text-Based Real Image Editing with Diffusion Models

https://openaccess.thecvf.com/content/CVPR2023/papers/Kawar_Imagic_Text-Based_Real_Image_Editing_With_Diffusion_Models_CVPR_2023_paper.pdfhttps://imagic-editing.github.io/ 问题引入 针对的是text based image editing问题&#xff0c;可以解决non rigid edit&am…

进程的了解

目录 一、进程控制块抽象&#xff08;PCB Process Control Block&#xff09; 1.pid&#xff1a;进程的身份标识 2.内存指针&#xff1a; 3.文件描述符表 进程的调度&#xff08;额外知识&#xff0c;不是进程属性&#xff09;&#xff1a; 4.进程的状态&#xff1a; 5.…

学习threejs,通过THREE.Raycaster给模型绑定点击事件

&#x1f468;‍⚕️ 主页&#xff1a; gis分享者 &#x1f468;‍⚕️ 感谢各位大佬 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍⚕️ 收录于专栏&#xff1a;threejs gis工程师 文章目录 一、&#x1f340;前言1.1 ☘️THREE.Raycaster光线投射概…

Go语言基础学习(Go安装配置、基础语法)

一、简介及安装教程 1、为什么学习Go&#xff1f; 简单好记的关键词和语法&#xff1b;更高的效率&#xff1b;生态强大&#xff1b;语法检查严格&#xff0c;安全性高&#xff1b;严格的依赖管理&#xff0c; go mod 命令&#xff1b;强大的编译检查、严格的编码规范和完整的…

图神经网络

定义&#xff1a; 对图上所有的属性&#xff0c;包括顶点、边、全局、上下文进行的一个可以优化的变换&#xff0c;该变换可以保存住图的对称信息&#xff08;将顶点进行另外一个顺序的排序后&#xff0c;结果不变&#xff09; Message passing neural network&#xff1a;使…

Java爬虫API:获取商品详情数据的利器

为什么选择Java爬虫API 强大的库支持&#xff1a;Java拥有丰富的网络编程库&#xff0c;如Apache HttpClient、OkHttp等&#xff0c;这些库提供了强大的HTTP请求功能&#xff0c;使得发送请求和处理响应变得简单。高效的数据处理&#xff1a;Java的数据处理能力&#xff0c;结…

使用Yolov10和Ollama增强OCR

1. 训练自定义 Yolov10 数据集 利用物体检测增强 OCR 的第一步是在数据集上训练自定义 YOLO 模型。YOLO&#xff08;只看一遍&#xff09;是一种功能强大的实时对象检测模型&#xff0c;它将图像划分为网格&#xff0c;使其能够在一次前向传递中识别多个对象。这种方法非常适合…

【某农业大学计算机网络实验报告】实验二 交换机的自学习算法

实验目的&#xff1a; &#xff08;1&#xff09;理解交换机通过逆向自学习算法建立地址转发表的过程。 &#xff08;2&#xff09;理解交换机转发数据帧的规则。 &#xff08;3&#xff09;理解交换机的工作原理。 实验器材&#xff1a; 一台Windows操作系统的PC机。 实…

Python|基于Kimi大模型,实现上传文档并进行“多轮”对话(7)

前言 本文是该专栏的第7篇,后面会持续分享AI大模型干货知识,记得关注。 假设有这样的需求,需要你通过python基于kimi大模型,上传对应的文档并根据对应的prompt提示词,进行多轮对话。此外,还需要将kimi大模型生成的内容进行存储。具体场景,如下图所示: 也就是说,当我们…

Kamailio-Sngrep 短小精悍的利器

一个sip的抓包小工具&#xff0c;在GitHub上竟然能够积累1K的star&#xff0c;看来还是有点东西&#xff0c;当然官方的友链也是发挥了重要作用 首先送上项目地址&#xff0c;有能力的宝子可以自行查看 经典的网络抓包工具有很多&#xff0c;比如&#xff1a; Wireshark&…

KASan部署、使用与原理分析

文章目录 前言1、概述2、使用方法3、测试用例3.1、检测加载的内核模块3.2、检测调用的内核模块3.3、通过系统调用检测3.4、检测编译到Linux内核中的内核模块 4、工作原理4.1、影子内存&#xff08;Shadow Memory&#xff09;4.2、内存状态&#xff08;Memory States&#xff09…

Go小技巧易错点100例(十八)

正文&#xff1a; 使用下划线增加数字可读性 有时候我们代码里会定义很长的数字&#xff0c;虽然计算机程序能支持很大的数据的计算&#xff0c;但是对我们来说&#xff0c;可读性是一个需要考虑的点&#xff0c;特别是1后面全是0的时候。 但是这个问题在Go语言中是可以通过…

使用js和canvas实现简单的网页打砖块小游戏

玩法介绍 点击开始游戏后&#xff0c;使用键盘上的←→控制移动&#xff0c;小球会不停移动&#xff0c;板子触碰小球时会反弹&#xff0c;碰撞到砖块时会摧毁砖块&#xff0c;如果没有用板子接住小球就游戏失败 代码实现 代码比较简单&#xff0c;直接阅读注释即可&#x…

Leetcode—1226. 哲学家进餐【中等】(多线程)

2024每日刷题&#xff08;185&#xff09; Leetcode—1226. 哲学家进餐 C实现代码 class DiningPhilosophers { public:mutex mx;DiningPhilosophers() {}void wantsToEat(int philosopher,function<void()> pickLeftFork,function<void()> pickRightFork,functi…