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