If I realized your question, here is example for approach, that pretty much works for me. This approach helps to separate interface and implementation. "Interface" module.
-module(contract).
-export([
new/2,
do_something/2
]).
%% Behavioural callbacks definition. Each of "derived" modules should implement it.
-callback new(Arg :: any()) -> {ok, ImplState :: any()} | {error, Reason :: atom()}.
-callback do_something( Arg :: any(), ImplState :: any() ) -> {ok, ReturnVal :: any(), NewImplState :: any()} | {error, Reason :: atom()}.
%% Opaque state to hold implementation details
-record(
contract_impl, {
impl_module :: module(),
impl_state :: any()
}
).
%% Interface for creation "polymorphic" instance, like base-class constructor.
new(ImplModule, ImplInitArgs) ->
case ImplModule:new(ImplInitArgs) of
{ok, State} ->
{ok,
#contract_impl {
impl_module = ImplModule,
impl_state = State
}
};
{error, Reason} ->
{error, Reason}
end.
%% Interface function, like an abstract method in OOP.
do_something(
Arg,
#contract_impl {
impl_module = ImplModule,
impl_state = ImplState
} = ContractImpl
) ->
case ImplModule:do_something(Arg, ImplState) of
{ok, ReturnVal, NewState} ->
{ok, ReturnVal, ContractImpl#contract_impl{ impl_state = NewState }};
{error, Reason} -> {error, Reason}
end.
5条答案
按热度按时间oyt4ldly1#
虽然其他人提到了 * behavior * 特性,但它只是一个小的帮助,用于确保实现回调结构的模块中的所有函数。如果您有两个实现,
a
和b
,并且都实现了相同的函数,您可以静态地用a
替换调用模块中的b
。对于有更好实现的静态配置,这是优选的。如果问题是动态性质的,你可以
然后在代码集
Mod
中进行适当的调用,这样可以在程序运行时动态地控制要调用哪个模块,但并不完全清楚您需要哪一个。5jvtdoz22#
多态性的一个很好的例子是
qlc
模块和结构table
。请参阅ets
、dets
、mnesia
等中的各种M:table/1,2
实现。例如在shell中尝试ets:table(ets:new(foo, [set])).
,并查看qlc
文档和示例。ttvkxqim3#
由于Erlang是动态类型的,函数保护(
when … ->
位)是表达多态性的方式。例如:
uurity8g4#
也许可以看看行为概念。至少对我来说,在接口定义和多个实现模块方面与OOP有一点相似之处。
qhhrdooz5#
If I realized your question, here is example for approach, that pretty much works for me. This approach helps to separate interface and implementation.
"Interface" module.
Some implementation example (like derived class).
Now you can do the following:
I hope this helps.