我们可以完全实现一个运算,而不需要查看任何组合运算的具体实现。就像你在数学中操作代数表达式一样。
假设将generateTrades作为领域服务 TradingService 的一部分。其目的是生成当天发生的所有交易(操作的输入),并由用户(操作的输入)在证券交易机构的后台执行。
trait TradingService:
/** 按特定用户生成当天的交易。具体步骤如下 * * 1.查询当天的所有执行情况 * 2.按执行顺序分组 * 3.对于每个订单号,从订单详情中获取账号 * 4.将交易分配到客户账户 * 5.存储交易 */ def generateTrades( date: LocalDate, userId: UserId ): ZStream[Any, Throwable, Trade] = queryExecutionsForDate(date) // 1 .groupByKey(_.orderNo): // 2 case (orderNo, executions) => executions .via(getAccountNoFromExecution) // 3 .via(allocateTradeToClientAccount(userId)) // 4 .via(storeTrades) // 5
/** 3、从执行流中获取客户账号 */ def getAccountNoFromExecution: ZPipeline[Any, Throwable, Execution, (Execution, AccountNo)]
/**4、从执行中生成交易并分配到相关客户账户 */ def allocateTradeToClientAccount(userId: UserId): ZPipeline[Any, Throwable, (Execution, AccountNo), Trade]
/**5、将交易持久化到数据库并返回存储的交易 */ def storeTrades: ZPipeline[Any, Throwable, Trade, Trade]
/**1、将交易持久化到数据库并返回存储的交易 */ def queryExecutionsForDate(date: LocalDate): ZStream[Any, Throwable, Execution]
|
在下面的示例中,请注意构成代数建模核心的以下 2 个原则:
- 方法规范中作为注释提到的步骤序列,与实现 generateTrades 时使用的操作类型一一对应。上面代码中注释了实现中的步骤 1、2、3、4、5、6。
- generateTrades 的实现与我们在此使用的 queryExecutionsForDate、getAccountNoFromExecution 等操作的实现完全分离。只需遵循这些操作的类型,并使用适当的组合器进行组合即可。