隐藏erlang中常见接口背后的不同实现

时间:2014-04-09 20:45:30

标签: erlang otp

我有一段erlang代码,应该从db中读取一些值,并且应该支持几个dbs。我希望我的代码在某种程度上不依赖于db,所以我实现了两个不同的gen_servers,它们使用相同的atom(db_handler)注册。我决定应该从哪个版本开始读取.app文件。

两个gen_servers公开了一个常见的handle_call,所以我可以在我的应用程序的其他部分使用类似的东西:

gen_server:call(db_handler, {do_something, "value1", "value2"})

这很有效,但它仍然强烈地与新数据库的每个和任何未来实现应该是gen_server的事实相关联。

我正在考虑使用!运算符并处理handle_info中的命令,但我认为可以使用更好的解决方案(可能通过另一个模块?)。

有人能给我一些关于在erlang中处理这类事情的更好方法的见解吗?

2 个答案:

答案 0 :(得分:2)

为每个数据库服务器添加一个通用接口来抽象调用:

-module(db_server1).

...

do_something([Value1,Value2]) -> gen_server:call(db_handler, {do_something, "value1", "value2"}).

...

另一个不使用gen服务器的人

-module(db_server2).

...

do_something([Value1,Value2]) -> something_else({do_something, "value1", "value2"}).

...

创建一个新进程(gen_server:o),它接收作为init参数的param,用于选择db服务器并将其存储在其状态中(例如db_server2),

对于每个do_something函数,实现如下函数:

do_something(Value1,Value2) -> gen_server:call(db_handler, {do_something, ["value1", "value2"]}).

...

handle_call({Func, Args}, _From, DB_server) ->
    R = DB_server:F(Args),
    {reply, R, DB_server}.
对于非阻塞接口,使用强制转换或等效的

也是一样的

答案 1 :(得分:0)

每个数据库驱动程序都可以是一个库模块,用于公开gen_server的函数。

handle_call({do_something, Driver, Value1, Value2}, _From, State) ->
  Reply = Driver:do_something(Value1, Value2),
  {reply, Reply, State}.