数据流在事件总线实现中的处理
1 数据流图简介
在分析阶段:
数据流图用于界定系统上下文范围和建立业务流程的加工说明,自顶向下对系统进行功能分解;
指明数据在系统内移动变换;
描述功能及加工规约。
数据字典用于建立业务概念有组织的集合,是模型核心库,
有组织的系统相关数据元素列表,使涉众对模型中元素有共同的理解。
在设计阶段:
结构化设计根据不同的数据流图类别分别做变换和事务映射来初始化系统结构图;
根据数据字典中的数据存储描述来建立数据库存储设计。
- 数据流图定义和属性
- 数据流图(Data Flow Diagram, DFD)的定义:
数据流图是用于描述系统如何处理输入和输出数据的一种图形化表示方法。它通过显示数据在系统各部分之间的流动方式,帮助分析系统的功能和数据处理过程。DFD主要用于系统分析阶段,直观地展示数据在系统中流动的过程。
- 数据流图的基本组成部分:
外部实体(External Entity):代表系统外部与系统交互的对象,比如用户、其他系统等。
数据流(Data Flow):表示数据在不同实体或处理单元之间的流动。
处理单元(Process):代表系统中对输入数据进行处理并产生输出的部分。
数据存储(Data Store):表示系统内部保存数据的位置,可能是数据库或文件系统等。
- 数据流图的层次分类:
上下文图(Context Diagram):最高层次的DFD,展示系统与外部实体之间的交互。
零级图(Level 0 DFD):细化的DFD,展示系统内部的主要处理单元。
分层数据流图(Level n DFD):在零级图基础上进一步分解的详细数据流图。
2 事件驱动的顶流图的功能和实现
假设我们现在需要做一个付款结算功能并计算佣金,一个事件驱动的顶流图系统可以通过Golang语言实现,处理以下功能步骤:
申请付款
计算佣金
验证订单
事件驱动系统是通过事件触发来推动工作流执行的系统。事件表示系统中发生的一些操作或状态改变,处理这些事件的逻辑称为“事件处理器”。常见的事件驱动架构中,事件发生后由事件处理器异步地处理,不同模块之间通过事件进行解耦。
我们可以使用事件总线模式来实现数据流图的关键步骤,即申请付款、计算佣金和验证订单。
3 代码实现
下面是一个简单的事件驱动顶流图的实现,采用事件总线模式来处理三个步骤。
申请付款
计算佣金
验证订单
事件总线:我们实现了一个简单的EventBus,用于注册和发布事件。Subscribe函数用来注册事件的处理器,Publish函数用于发布事件并通知注册的处理器。
// 定义事件总线结构
type EventBus struct {
handlers map[string][]func(interface{})
lock sync.Mutex
}
// 创建新的事件总线
func NewEventBus() *EventBus {
return &EventBus{
handlers: make(map[string][]func(interface{})),
}
}
// 注册事件处理器
func (eb *EventBus) Subscribe(eventName string, handler func(interface{})) {
eb.lock.Lock()
defer eb.lock.Unlock()
// 将事件处理器注册到指定事件名的列表中
if _, found := eb.handlers[eventName]; !found {
eb.handlers[eventName] = []func(interface{}){}
}
eb.handlers[eventName] = append(eb.handlers[eventName], handler)
}
// 发布事件
func (eb *EventBus) Publish(eventName string, data interface{}) {
eb.lock.Lock()
defer eb.lock.Unlock()
if handlers, found := eb.handlers[eventName]; found {
// 触发每个处理器
for _, handler := range handlers {
handler(data)
}
}
}
订单结构体(Order):用于存储订单的信息,包括订单ID、金额、是否已验证、佣金、是否已付款等。
// 定义订单和支付申请的结构
type Order struct {
ID string
Amount float64
IsVerified bool
Commission float64
IsPaid bool
}
功能步骤:
申请付款:首先执行付款申请操作,之后通过事件总线发布“paymentRequested”事件。
计算佣金:一旦付款申请完成,会触发佣金计算,佣金按订单金额的10%计算。
验证订单:付款完成后,还会验证订单,标记订单为已验证。
事件流:整个系统基于事件驱动模式。每当申请付款完成时,会自动触发佣金计算和订单验证,模块之间通过事件解耦。
// 步骤1: 申请付款
func requestPayment(eventBus *EventBus, order *Order) {
fmt.Printf("申请付款: 订单ID: %s, 金额: %.2f\n", order.ID, order.Amount)
order.IsPaid = true
// 触发“申请付款完成”事件
eventBus.Publish("paymentRequested", order)
}
// 步骤2: 计算佣金
func calculateCommission(order *Order) {
if order.IsPaid {
order.Commission = order.Amount * 0.1 // 假设佣金为订单金额的10%
fmt.Printf("计算佣金: 订单ID: %s, 佣金: %.2f\n", order.ID, order.Commission)
// 触发“佣金计算完成”事件
}
}
// 步骤3: 验证订单
func verifyOrder(order *Order) {
if order.IsPaid {
order.IsVerified = true
fmt.Printf("验证订单: 订单ID: %s 已验证通过\n", order.ID)
}
}
-
验证和调用
func main() { // 创建一个新的事件总线 eventBus := NewEventBus() // 创建一个订单 order := &Order{ID: "22345", Amount: 900.00} // 注册事件处理器 eventBus.Subscribe("paymentRequested", func(data interface{}) { order := data.(*Order) calculateCommission(order) }) eventBus.Subscribe("paymentRequested", func(data interface{}) { order := data.(*Order) verifyOrder(order) }) // 启动事件流 requestPayment(eventBus, order) // 打印订单状态 fmt.Printf("订单处理完成: 订单ID: %s, 验证状态: %t, 佣金: %.2f\n", order.ID, order.IsVerified, order.Commission) }
可以进一步扩展此事件驱动系统,加入更多的事件和处理逻辑,例如:退款流程、促销折扣计算等。
为了提高性能,可以采用异步处理方式(例如使用Goroutines)来处理事件,避免阻塞。
建立手动和自动系统需求
4 需要注意的关键
在这个设计中,事件驱动架构通过事件总线将不同的功能步骤解耦,各功能通过事件触发有序执行。同时,Golang的并发能力可以进一步优化事件驱动模型,使系统更加高效、响应快速。
这样一个基于事件驱动的数据流图架构,可以很好地体现出数据流图中的数据流动和处理过程,每个处理步骤作为一个事件处理器,与外部实体和系统模块交互,数据则通过事件在不同处理单元之间传递和变更。
- 数据流图的意义
用于表达系统的逻辑信息流
用于寻找系统需求
简单、以理解的图形符号
需要注意层间平衡点:
数据流个数一致,方向一致图内平衡:有输入无输出的黑洞,有输出无输入的奇迹,输入不足的灰洞
黑洞 - 程序步骤可能有输入流,但没有输出流。
奇迹 - 一个程序步骤可能有输出流,但没有输入流。
灰孔 - 程序步骤的输出可能大于其输入的总和
- 点赞
- 收藏
- 关注作者
评论(0)