erlang多态性:同一合同的多个实现

时间:2014-03-10 22:52:36

标签: erlang polymorphism

请告知:Erlang有什么方法可以将合同中的实现分开,以及如何在合同之间切换?

感谢您的提示! YF

5 个答案:

答案 0 :(得分:2)

多态性的好例子是qlc模块和结构table。请参阅M:table/1,2etsdets等各种mnesia实施。以shell中的ets:table(ets:new(foo, [set])).为例,查看qlc文档和示例。

答案 1 :(得分:1)

由于Erlang是动态类型的,function guardswhen … ->位)是表达多态的方式。

E.g:

len (T) when is_tuple(T) -> size(T);
len (L) when is_list(L) -> length(L).

答案 2 :(得分:1)

也许看看behaviours概念。至少就我而言,在具有接口定义和多个实现模块方面与OOP的相似性很小。

答案 3 :(得分:1)

虽然其他人提到行为功能,但它只是一个小帮手,可确保您在模块中实现回调结构的所有功能。如果您有两个实现ab,并且两者都实现了相同的功能,则可以在调用模块中静态替换a b。对于具有更好实现的静态配置,这是更可取的。

如果问题更具动态性,您可以这样做

 Mod = a,
 Mod:f(Args).

然后在代码集Mod中进行适当的处​​理。这使您可以动态控制程序运行时要调用的模块。你想要的两个中哪一个并不完全清楚。

答案 4 :(得分:0)

如果我意识到你的问题,这里是方法的例子,那对我来说非常有用。这种方法有助于分离界面和实现。

“界面”模块。

-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.

一些实现示例(如派生类)。

-module(foo).

-behaviour(contract).

-export([
  new/1,
  do_something/2
]).

-record(
  foo_state, {
    repeat_count
  }
).

new(Options) ->
  {ok,
    #foo_state{
      repeat_count = proplists:get_value(repeat_count, Options)
    }
  }.

do_something(Arg, #foo_state{ repeat_count = RepeatCount } = State) ->
  Result = [ io_lib:format("Foo ~p", [Arg]) || _Index <- lists:seq(1, RepeatCount) ],
  {ok, Result, State}.

现在您可以执行以下操作:

usage_example() ->
  {ok, State} = contract:new(foo, [{repeat_count, 15}]),
  {ok, Result, NewState} = contract:do_something("bar", State),
  ok.

我希望这会有所帮助。