0

我正在构建一个可以以两种模式运行的应用程序。沙盒模式和生产模式。

在沙盒模式下,我想在我的 gen_server 中对数据库进行许多检查:如果表不存在,则创建它;如果列不存在,则添加它;如果列类型不允许我要存储的值然后更改它,等等。

在生产模式下,如果表不存在或列与值的类型不匹配,则会失败,没关系。

因此,为了避免像“case State#state.is_sandbox of true -> ...”这样的繁琐代码,我想为我的 gen_server 设置两个不同的模块,并且我想在 handle_call 或句柄信息。

实际上,我只是想从沙盒转到生产,但我认为如果它以这种方式工作,它可以向后工作。

谢谢。

4

4 回答 4

3

您可以将module模块名称添加到 gen_server 中的状态中。然后,您将需要 2 个模块 - 沙盒和生产,它们都实现了相同的功能(您可以为它创建一个行为)。

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}).

沙盒模块也是如此。

带有 gen_server 的回调示例module

handle_call(Msg, _From, #state{module = Module} = State) ->
    Module:function(Msq),
    {reply, ok, State}.

function必须在沙盒和生产模块中实现。

于 2013-02-06T21:12:41.710 回答
1

您可以使用获取模块名称os:getenv/1(当然在此之前您必须在不同的环境中设置不同的名称)

于 2013-02-06T18:42:18.353 回答
1

您可以将 agen_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().

在此设置中,erlang 会根据沙箱变量的值自动选择要触发的正确子句,而无需定义单独的处理程序或使用 case 语句。以这种方式在函数子句中绑定变量也是提高效率的好习惯(因为变量绑定在函数体之外,绑定过程在调度程序中完成,因此不计入函数的执行时间,而所有匹配都是在一个案例中的函数体内完成的)

于 2013-02-06T19:11:15.797 回答
1

而不是gen_server你可以使用gen_fsm有限状态机,它可以很容易地处理这种情况。您只有多个状态,它们根据状态调用不同模块中的函数。它基本上为您完成所有处理,无需携带显式state参数。这基本上是手动实现 FSM。

于 2013-02-07T20:52:24.157 回答