我正在构建一个应用程序,可以在两种模式下运行。沙箱模式和生产模式。
在沙箱模式下,我想在我的gen_server中对数据库进行许多检查:如果表不存在,则创建它;如果列不存在,则添加它;如果列类型不允许我要存储的值,则更改它,等等。
在生产模式下,如果表不存在或列与值的类型不匹配,它将失败,这是可以接受的。
因此,为了避免像"case State#state.is_sandbox of true -> ...“这样的繁琐代码,我希望为我的gen_server使用两个不同的模块,并且我希望在handle_call或handle_info中更改当前的模块。
实际上,我只想从沙箱转到生产环境,但我认为如果它以这种方式工作,它可以反向工作。
谢谢。
发布于 2013-02-07 05:12:42
您可以向gen_server中的状态添加module
,它是一个模块的名称。然后你将需要两个模块-沙箱和生产,它们都实现了相同的功能(你可以为它创建一个行为)。
gen_server回调将调用module:function
,它将是来自沙箱或生产模块的函数。module
可以在gen_server的init
函数中设置,要更改它,只需在gen_server中添加一个新函数:
use_production() ->
gen_server:cast(production).
....
handle_cast(production, State) ->
{noreply, State#state{module = production}).
沙箱模块也是如此。
使用module
的gen_server回调示例
handle_call(Msg, _From, #state{module = Module} = State) ->
Module:function(Msq),
{reply, ok, State}.
必须在沙箱和生产模块中实现function
。
发布于 2013-02-07 02:42:18
您可以使用os:getenv/1
获取模块名称(当然,在此之前您必须在不同的环境中设置不同的名称)
发布于 2013-02-07 03:11:16
您可以使用具有单个处理程序的gen_event
,这允许您返回一个swap_handler
元组(请参阅gen_event/handle_*)
而且,您不必在gen_server模型中使用case语句。如果您的州包含沙箱变量,则可以通过绑定标头中的沙箱值为回调函数定义不同的子句。例如:
handle_call(do_stuff, _From, State = #state{sandbox = true}) ->
do_sandbox_stuff();
handle_call(do_stuff, _From, State) ->
do_nonsandbox_stuff().
在function子句中绑定变量这种方式也是提高效率的良好实践(因为变量绑定在函数体之外,绑定过程在调度器中完成,因此不计入函数的执行时间,而所有匹配都在case中的函数体内部完成)
https://stackoverflow.com/questions/14736323
复制相似问题