在Erlang中扩展gen_事件行为
我正在编写一个事件管理器,它将使用许多不同的事件处理程序。此事件管理器将收到许多不同事件的通知。每个处理程序只处理某些事件,而忽略其余事件。每个处理程序还可以根据情况触发某些其他事件 例如,处理在Erlang中扩展gen_事件行为,erlang,gen-event,Erlang,Gen Event,我正在编写一个事件管理器,它将使用许多不同的事件处理程序。此事件管理器将收到许多不同事件的通知。每个处理程序只处理某些事件,而忽略其余事件。每个处理程序还可以根据情况触发某些其他事件 例如,处理Event1 -模块(第一个\u处理程序)。 -行为(gen_事件)。 ... handle_事件(Event1,State)->{ok,State}; 处理事件(u,State)->{ok,State}。 第二个处理Event2 -模块(第二个\u处理程序)。 -行为(gen_事件)。 ... 处理事
Event1
-模块(第一个\u处理程序)。
-行为(gen_事件)。
...
handle_事件(Event1,State)->{ok,State};
处理事件(u,State)->{ok,State}。
第二个处理Event2
-模块(第二个\u处理程序)。
-行为(gen_事件)。
...
处理事件(事件2,状态)->
gen_事件:通知(self(),Event1),
{好的,国家};
处理事件(u,State)->{ok,State}。
事件触发可以通过在处理程序的handle\u事件
中调用gen\u event:notify(self(),NewEvent)
来完成,但我更愿意将其抽象并导出,以便可以从事件管理器调用它
由于模式匹配、忽略事件和触发事件对于所有处理程序来说都是常见的,因此我是否可以扩展gen_event
行为来提供这些内置事件
我将从创建自定义行为的默认方式开始:
-模块(发电机新事件)。
-行为(gen_事件)。
行为信息(类型)->gen\u事件:行为信息(类型)。
我不确定下一步该怎么办。您安装的处理程序已经在事件管理器的上下文中运行,您启动事件管理器,然后将其安装到事件管理器中。所以,如果它们的handle-event函数抛出数据,它们已经做了您想要做的事情 您不需要扩展事件行为。你要做的是:
handle_event(Event, State) ->
generic:handle_event(Event, State).
然后让通用
模块处理通用部分。请注意,如果需要,您可以提供generic
一种回调此处理程序模块以实现专门处理程序行为的方法。例如:
generic:handle_event(fun ?MODULE:callback/2, Event, State)...
依此类推。您安装的处理程序已经在事件管理器的上下文中运行,您可以启动事件管理器,然后将其安装到事件管理器中。所以,如果它们的handle-event函数抛出数据,它们已经做了您想要做的事情 您不需要扩展事件行为。你要做的是:
handle_event(Event, State) ->
generic:handle_event(Event, State).
然后让通用
模块处理通用部分。请注意,如果需要,您可以提供generic
一种回调此处理程序模块以实现专门处理程序行为的方法。例如:
generic:handle_event(fun ?MODULE:callback/2, Event, State)...
等等。你到底想做什么?从你提供的例子中我无法理解。在第二个\u处理程序的
handle\u event/2
中,Event1
是未绑定的。另外,使用self()
有效吗?那不应该是经理的注册名吗。不确定是由管理器还是每个处理程序进程执行handle\u event/2
(但后者更有意义)
通过实现gen_new_event
模块,您实现的是处理程序(即回调模块),而不是事件管理器。您拥有-behavior(gen\u event)
这一事实意味着您要求编译器检查gen\u new\u event
是否实际实现了gen\u event:behavior\u info(回调)
列出的所有函数,从而使gen\u new\u event
成为一个合格的处理程序,您可以通过gen\u event:add\u handler(manager\u registered\u name,gen\u new\u event,[])将其添加到事件管理器中。
现在,如果去掉-行为(gen_事件)
,gen_new_事件
不再需要实现以下功能:
35> gen_event:behaviour_info(callbacks).
[{init,1},
{handle_event,2},
{handle_call,2},
{handle_info,2},
{terminate,2},
{code_change,3}]
通过添加更多功能,您可以将gen\u new\u event(gen\u new\u event)
作为一种行为(即接口),您需要任何使用-行为(gen\u new\u event)
的模块来实现:
-module (gen_new_event).
-export([behaviour_info/1]).
behaviour_info(callbacks) ->
[{some_fun, 2}, {some_other_fun, 3} | gen_event:behaviour_info(callbacks)].
现在,如果在某些模块中,例如-module(example)
,添加属性-behavior(gen\u new\u event)
,那么模块example
将必须实现所有gen\u event
回调函数+一些乐趣/2
和一些其他乐趣/3
我怀疑这正是您想要的,但您的最后一个示例似乎表明您想要实现一种行为。请注意,实现行为所做的一切都是要求其他模块实现某些功能,如果它们使用-behavior(您的行为)
(另外,如果我理解正确,如果您想扩展gen_event
,那么您可以总是简单地复制gen_event.erl
中的代码并扩展它……我想,但这真的是您尝试做的事情所必需的吗?)
编辑
目标:从gen_事件实现中提取通用代码。例如,在每个gen_事件中都有一个handle_event/2子句
一种方法是:可以使用参数化模块。此模块将实现gen_事件行为,但仅实现所有gen_事件回调模块应具有的常见行为。任何非“公共”的内容都可以委托给模块的参数(您可以将该参数绑定到包含gen_事件回调的“自定义”实现的模块名称)
例如
然后,您将实现一个或多个gen_事件模块,并将其插入抽象的gen_事件中。假设其中一个是一个gen_事件
那么你应该能够做到:
AGenEvent = abstract_gen_event:new(a_gen_event). %% Note: the function new/x is auto-generated and will have arity according to how many parameters a parameterized module has.
然后,我想您可以将AGenEvent传递给gen\u event:add\u处理程序(一些\u ref,AGenEvent,[]),它应该可以工作,但请注意,我从未尝试过这种方法
也许您也可以使用宏来解决这个问题,或者(但这有点过分了)在编译时使用parse_transform/2进行一些操作。不过,请想一想。先看看这个参数化解决方案是如何实现的
第二次编辑
(注意:我不确定是否应该删除本节内容之前的所有内容。请让m
-module(tmp).
parse_transform(Forms, Options) ->
io:format("~p~n", [Forms]),
Forms.
-module(generic).
gen(Event, State) ->
io:format("Event is: ~p~n", [Event]),
{ok, State}.
c(tmp).
c(generic, {parse_transform, tmp}).
[{attribute,1,file,{"../src/generic.erl",1}},
{attribute,4,module,generic},
{attribute,14,compile,export_all},
{function,19,gen,2,
[{clause,19,
[{var,19,'Event'},{var,19,'State'}],
[],
[{call,20,
{remote,20,{atom,20,io},{atom,20,format}},
[{string,20,"Event is: ~p~n"},
{cons,20,{var,20,'Event'},{nil,20}}]},
{tuple,21,[{atom,21,ok},{var,21,'State'}]}]}]},
{eof,28}]
{ok,generic}