考虑一个例如处理客户结账的服务/功能的例子,涉及许多步骤:服务器应该(例如)检查库存,验证欺诈,收取信用卡,扣除库存,关闭购买,发送电子邮件客户,通知后端/处理程序/仓库,然后返回http请求。
在面向对象的语言中,我通过构建服务对象,让它以一种方式同步并按顺序执行这些步骤,在出现问题时进行分支(甚至可能使用状态机)。
然而,当我想到如何用像Elixir这样的语言解决这个问题时,我能想出的唯一解决方案就是长链管道 - 感觉就像Elixir世界的反模式,特别是当你考虑分支时。
我的第二个想法是,每一步都是它自己的功能(感觉惯用),并且需要额外的购买状态参数。在这种情况下,validate_fraud
操作可以使用charge_credit_card
信息调用{purchase, fraud_passed}
,然后charge_credit_card
会在完成后调用行中的下一个。然而,这意味着每个函数都需要知道它在一个链中的位置,这又感觉就像一个气味(然后每个函数都需要有逻辑来处理不同的传入'状态')。
Elixir处理OO世界用服务对象解决的情况的惯用方法是什么?
答案 0 :(得分:2)
语言的功能性并不意味着任何业务规则。如果链接看起来像你所描述的那样,没有任何价值(实际上也没有可能)使步骤异步,因为validate_fraud
在inventory_check
之前没有任何意义,也不会在{{1}之后}。
在这种情况下,解决方案与OO服务非常相似:可能会产生一个流程(在这种特殊情况下为Task
),它将管理所有步骤:
charge_credit
现在任务有一个很好的功能,人们可能会检查它是否已用Task.yield/2
完成,并拥有自己的超时。调用者代码可能只是简单地调用task = Task.async(fn ->
check inventory()
|> validate fraud()
|> charge()
|> deduct_inventory()
|> close_purchase()
|> email_customer()
|> notify_handler()
|> return_http_request()
end)
来阻止调用者,直到任务完成,或者更好的是,它可能会等待,例如,使用Task.await/2
等3秒,并且如果已完成,则返回结果,如果执行时间较长,则带有“承诺”。