在 elixir 中共享相同功能的设计模式是什么?
例如,
我有一个应用程序,它“采用”一个结构,将结构“转换”为不同的格式并将其“推送”到一些存储中。
我有 3 个结构通过这个管道,有 3 个转换规则和 3 个存储。
该项目使用 gen_stage
包,它具有以下结构:
(book) |producer| -> |transformer| -> |indexer|
(article)|producer| -> |transformer| -> |indexer|
(post) |producer| -> |transformer| -> |indexer|
每个阶段都是一个单独的模块,即 Book.Producer、Book.Transformer、Book.Indexer。
同一垂直线上的阶段执行 与 相同的事情,但具有不同的实体。 IE。 Book.Producer 从数据库中取书,Article.Producer 从数据库中取文章等。
“从数据库中获取”部分相当通用,可以在所有管道中重复使用,即
alias Experimental.GenStage
defmodule Books.Producer do
use GenStage
def start_link do
GenStage.start_link(__MODULE__, [], name: __MODULE__)
end
def init([]) do
{:producer, []}
end
def handle_demand(demand, processed) when demand > 0 do
events = Repo.all Book
{:noreply, events, processed ++ events}
end
end
转换器在从数据库生成的实体上运行一个函数。索引器将转换器记录推送到另一个存储中。
在带有大量重复的幼稚方法中,我可以有 9 个(3 个用于书籍,3 个用于文章,3 个用于发布)模块来完成所有这些步骤。
我有什么选择来提取类似的功能并在使用它的模块之间共享它。
也许我可以通过在初始化阶段传递参数来配置它,或者仍然有 9 个模块,但将函数重构到另一个模块中。最佳做法是什么?
最佳答案
对于您提到的情况,一个可能的选择是在启动流程时(例如,从监督树)传递您尝试从中获取的架构模块(即 Book
、 Post
等)作为选项。您将在对 start_link
的调用中收到这些选项,然后可以在调用 GenStage.start_link
时将它们作为第二个参数传递。
这将导致这些选项在 GenStage 启动时作为参数传递给 init
。此时,您可以将该模块置于状态(例如,与元组中的 processed
列表一起),以便在每次 handle_demand
调用时传递它。在那里,您最终可以将其用作调用 Repo.all
的参数。
模块可以像任何其他值一样传递,有时您可以利用它来重用代码 - 这是一个可能派上用场的示例!
您可以对流程的其他部分使用类似的方法 - 只需弄清楚哪些变化并在启动流程时将其指定为选项即可。例如,转换函数将是您第二步的一个选项的一个很好的候选者。有几种方法可以实现:
&BookTransformer.transform/1
; fn data -> transform_all_the(data) end
。 和模块一样,函数在 Elixir 中是一等公民。它们可以像值一样传递。这是函数式编程语言中常见的代码重用模式。
关于elixir - 在 elixir 中共享相同功能的设计模式是什么?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/39072491/