我有一段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中处理这类事情的更好方法的见解吗?
答案 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}.