分析一下之前的代码,可以注意到,server的功能其实是非常类似的,我们可以把公共的部分抽取出来,把不同的部分单独实现,做到一定程度上的复用,erlang支持动态的使用变量,例如:
这样的代码会启动my_server,借助这个功能,我们可以把模块名作为参数传入,还可以使用模块名作为进程的注册名,于是,代码就便成了这样
使用这段代码,我们只要完成一个回调模块就可以了,例如:
运行一下——
Mod = my_server.
Mod:start().
这样的代码会启动my_server,借助这个功能,我们可以把模块名作为参数传入,还可以使用模块名作为进程的注册名,于是,代码就便成了这样
% my_server5.erl %
-module(my_server5).
-export([start/2,stop/1]).
-export([init/2]).
-export([request/2]).
% 启动一个模块,注册服务的名称为模块名称 %
start(Mod,Env) -> spawn(my_server5,init,[Mod,Env]).
stop(Mod) -> Mod ! stop .
%请求响应式接口,具体的实现实际上依靠Mod模块的 handle_request 方法%
request(Mod, Request) ->
Mod ! { request, self(), Request },
ok.
% 初始化服务,注册名称,启动init方法,初始化服务时接受一个参数 %
init(Mod, Env) ->
register(Mod,self()),
State = Mod:init(Env),
loop(Mod,State).
% 实际执行体 %
loop(Mod, State) ->
receive
{ request,From,Request } ->
{Res,State2} = Mod:handle_request(Request,State),
From ! {Mod, Res},
loop(Mod,State2);
stop ->
io:format("process stopped.last state is ~p~n",[State])
end.
使用这段代码,我们只要完成一个回调模块就可以了,例如:
% my_handle1.erl %
-module(my_handle1).
-export([init/1,handle_request/2]).
init(State) -> State.
handle_request(Request,State) ->
io:format("request to callback1: ~p~n",[Request]),
{"ok",State}.
运行一下——
Eshell V5.7.2 (abort with ^G)
1> c(my_server5),c(my_client),c(my_handle1).
{ok,my_handle1}
2> C = my_client:start(),my_server5:start(my_handle1,"init").
<0.49.0>
3> my_server5:request(my_handle1, "hello").
request to callback1: "hello"
ok
4> my_server5:stop(my_handle1).
process stopped.last state is "init"
stop