前言
有时候,我们希望一些模块能够分享一个开放的 API 接口,在 Erlang 里的解决方案就是行为(behavior)。行为承担了两大角色:
- 定义一组需要被实现的函数
- 检查这组函数是否真的被实现
Erlang 预定义了好一些行为,例如 gen_server,gen_fsm等,但这里我们演示怎么定义自己的行为
定义行为
用worker 模块来具体实现一组行为。这些 workers 都应该实现两个函数:init/1 和 perform/2。
-module(worker).
-author("01").
%% ----------------------------------------------------
%% Description: 创建
%% ----------------------------------------------------
-callback init(State) -> Reply when
State :: term(),
Reply :: {'ok', NewState} | {'error', Reason},
NewState :: term(),
Reason :: term().
%% ----------------------------------------------------
%% Description: 执行
%% ----------------------------------------------------
-callback perform(Args, State) -> Reply when
Args :: term(),
State :: term(),
Reply :: {'ok', Result, NewState}| {'error', Reason, NewState},
Result :: term(),
Reason :: term(),
NewState :: term().
这里定义了 init/1 作为一个接收任何参数,并返回一个 值为 {ok, State} 或 {error, Reason} 的 Tuple(元组)。这是一个很典型的初始化方式。perform/2 函数则接收一些参数,以及初始化后的状态。perform/2 的返回值则是 {ok, Result, State} 或者 {error, Reason, State}
实现行为的方式
定义好行为,下一步使用它来创建一些拥有同样的开放的 API 接口的模块了。在模块中添加行为非常简单,只需要使用 -behaviour()。
一个能压缩一个数组的文件的 worker
-module(compressor).
-author("01").
-behaviour(worker).
-export([init/1, perform/2]).
%% ----------------------------------------------------
%% Description: 创建
%% ----------------------------------------------------
init(Options) ->
{'ok', Options}.
%% ----------------------------------------------------
%% Description: 执行
%% ----------------------------------------------------
perform(Payload, Options) ->
compress(Payload, Options).
%% ----------------------------------------------------
%% Description: 压缩函数
%% ----------------------------------------------------
compress({Name, Files}, Options) ->
zip:create(Name, Files, Options).
测试
14> c(worker).
{ok,worker}
15> c(compressor).
{ok,compressor}
16> compressor:init([]).
{ok,[]}
17> compressor:perform({worker,[“./worker.erl”]},[]).
{ok,worker}
就将worker.erl压缩为worker了
如果不实现开放的接口呢?
-module(work_test).
-author("01").
-behavior(worker).
-export([do_some/0]).
do_some()->
ok.
编译后会出现警告
总结
行为模式通过提供接口和约定来实现代码重用、解耦合、可替换性、扩展性和统一的抽象层,从而提高代码的可维护性、可扩展性和灵活性。它是一种有助于构建可靠和可扩展系统的良好编程实践。