如何在Elixir中指定编译时的模块实现

  • 本文关键字:编译 模块 实现 Elixir elixir
  • 更新时间 :
  • 英文 :


我有一个应用程序,应该支持多种类型的存储。目前,我希望它同时支持S3和swift。

现在是问题:我如何允许我的应用程序在加载时选择它将使用的后端(如中所示,配置将指定它是S3还是swift(?

在OOP中,我会有接口,并且可以注入依赖项。在这种情况下,显而易见的答案是GenServer。但我实际上并不需要一个完整的专用进程(它也应该充当我代码的瓶颈(。

我考虑过简单地将对模块的引用作为参数传递,但感觉有点不确定,因为从技术上讲,可能会传递不正确的实现。

因此,为了进一步指定:我如何根据配置(没有Genserver(将特定的后端(S3或swift(注入到我的代码中?

defmodule App.Filestorage do
@callback store(String.t) :: :ok | :error
end
defmodule App.S3 do
@behaviour App.Filestorage
@impl
def store(path), do: :ok 
end
defmodule App.Swift do
@behaviour App.Filestorage
@impl
def store(path), do: :ok
end
defmodule App.Foo do
def do_stuff()
# doing some stuff
App.Filestorage.store(result_file) # replace this with S3 or Swift
end
end

你走对了!要通过配置使用注入,您可以指定所选可执行模块的名称,并从配置中获取其名称以调用它:

config:
config :app, :filestorage, App.S3

defmodule App.Filestorage.Behaviour do
@callback store(String.t) :: :ok | :error
end
defmodule App.Filestorage do
def adapter(), do: Application.get_env(:app, :filestorage)
def store(string), to: adapter().store
end
defmodule App.S3 do
@behaviour App.Filestorage.Behaviour
@impl true
def store(path), do: :ok 
end
defmodule App.Swift do
@behaviour App.Filestorage.Behaviour
@impl true
def store(path), do: :ok
end
defmodule App.Foo do
def do_stuff()
# doing some stuff
App.Filestorage.store(result_file) # replace this with S3 or Swift
end
end

注意1:您可以将behavior(App.Filestorage.Behavior(和";实现";(App.Filestorage(模块,如果您想要

注意2:您可以使用module属性从配置中指定适配器,但要注意部署过程中的副作用,因为它将保存编译时的确切配置

注意3:如果按函数使用适配器规范,与示例中相同,您甚至可以在运行时通过更改配置来更改所选的实现

更多详细信息,请访问帖子:http://blog.plataformatec.com.br/2015/10/mocks-and-explicit-contracts/https://blog.carbonfive.com/lightweight-dependency-injection-in-elixir-without-the-tears/

最新更新