在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}