【问题标题】:Different views for same erlang record同一erlang记录的不同视图
【发布时间】:2021-05-18 08:16:50
【问题描述】:

假设我有记录

-record(expense, {uuid, amount, tags}).

我想要一个可显示的记录版本。标签字段包含标签唯一 ID。我想在表单上显示标签的名称而不是唯一的 ID。你会如何在 Erlang 中做到这一点?通常,在 OOP 语言中,您会使用 ViewModel 来拥有同一对象的不同可显示版本。

选项 1 使用不同数据格式的相同记录,但我认为它会破坏接口契约;人们将无法知道自己拥有哪个版本的记录。

选项 2 创建另一条记录

-record(expense_view1, {uuid, amount, tags}).

但它会创建很多重复的记录。

选项 3 使用元组或映射。如果我向记录中添加更多字段,则元组很难维护,并且映射不能保证字段名称的安全性。

【问题讨论】:

    标签: erlang


    【解决方案1】:

    标签字段包含标签唯一 ID。我想显示名字 表单上的标签而不是唯一 ID。

    这个怎么样:

    -module(a).
    -compile(export_all).
    
    -record(expense, {uuid, amount, tags}).
    
    show_action(#expense{uuid=UUID, amount=Amount, tags={A, B, C} }) ->
        TagConversions= #{1 => "Joe", 2 => "Tammy", 3 => "Bob"},
        A_Conv = maps:get(A, TagConversions, "Nathan"),
        B_Conv = maps:get(B, TagConversions, "Nathan"),
        C_Conv = maps:get(C, TagConversions, "Nathan"),
        io:format("~w, ~w, {~s,~s,~s}~n", 
                  [UUID, Amount, A_Conv, B_Conv, C_Conv]).
    
    
    go() ->
        Expense1 = #expense{uuid=1, amount=10, tags={1,2,3} },
        show_action(Expense1).
    

    在外壳中:

    12> c(a).  
    a.erl:2: Warning: export_all flag enabled - all functions will be exported
    {ok,a}
    
    13> a:go().
    1, 10, {Joe,Tammy,Bob}
    ok
    

    我想要一个可显示的记录版本。 但是会产生很多重复的记录。

    是的,但是在 OOP 中,您是否没有大量的 View 对象,其中包含 Model 对象中的全部或部分数据?

    选项 1 使用不同数据格式的相同记录,但我认为 它会破坏接口契约;一个人将无法知道 有哪个版本的记录。

    您可以构造记录,为标签ID对应的标签名称留一个空白点,然后在可能的情况下填写标签名称:

    -module(a).
    -compile(export_all).
    
    -record(tag, {id, name=""}).
    -record(expense, {uuid, amount, tags}).
    
    show_action(Expense = #expense{uuid=UUID, amount=Amount, tags={A, B, C} }) ->
        TagConversions= #{1 => "Joe", 2 => "Tammy", 3 => "Bob"},
        A_Conv = maps:get(A#tag.id, TagConversions, "Nathan"),
        B_Conv = maps:get(B#tag.id, TagConversions, "Nathan"),
        C_Conv = maps:get(C#tag.id, TagConversions, "Nathan"),
        io:format("~w, ~w, {~s,~s,~s}~n", 
                  [UUID, Amount, A_Conv, B_Conv, C_Conv]),
    
        Expense#expense{tags={
                          A#tag{name=A_Conv},
                          B#tag{name=B_Conv},
                          C#tag{name=C_Conv}
                         }}.
    go() ->
    
        Expense1 = #expense{uuid=1, amount=10, 
                            tags={#tag{id=1},
                                  #tag{id=2},
                                  #tag{id=3} }
                           },
    
        show_action(Expense1).
    

    在外壳中:

    5> c(a).
    a.erl:2: Warning: export_all flag enabled - all functions will be exported
    {ok,a}
    
    6> a:go().
    1, 10, {Joe,Tammy,Bob}
    {expense,1,10,{{tag,1,"Joe"},{tag,2,"Tammy"},{tag,3,"Bob"}}}
    

    【讨论】:

      【解决方案2】:

      您可以在访问功能中选择查看模式:

      -module (tuple).
      
      -export ([get/1,get/2,start/0,stop/0]).
      
      
      -record(expense, {uuid, amount, tags}).
      
      %%%%%%%%% Interfaces %%%%%%%%%
      
      % start the server with a static map
      start() ->
          Pid =spawn(fun() -> loop(#{1 => one, 2 => two, 3 => three}) end),
          register(server, Pid).
      
      stop() ->
          server ! stop.
      
      % By default for "external users" get the view with value
      get(T) ->
          get(T,value).
      
      % for "internal usage" it is possible to choose either the id view or the value view
      get(T,value) ->
          Values = lists:map(fun get_value/1, T#expense.tags),
          T#expense{tags = Values};
      get(T,id) ->
          T.
      
      %%%%%%%%% server %%%%%%%%%%
      % the server is in charge to store the id => value association
      % it could be also stored in an ETS, a database ...
      loop(Ids) ->
          receive
              stop ->
                  done;
              {From, get_value, Id} ->
                  % the choice is made to do not crash if the id does not exist
                  From ! {ok,maps:get(Id, Ids, undefined)},
                  loop(Ids)
          end.
      
      %%%%%%%%% private %%%%%%%%%
      
      get_value(Id) ->
          server ! {self(), get_value, Id},
          receive
              {ok,Value} ->
                  Value
          end.
      

      在shell中给出:

      1> c(tuple).                                                  
      {ok,tuple}
      2> rr(tuple).                                                 
      [expense]
      3> T = #expense{uuid = 12345, amount = 20000, tags = [1,3,4]}.
      #expense{uuid = 12345,amount = 20000,tags = [1,3,4]}
      4> tuple:start().                                             
      true
      5> tuple:get(T).                                              
      #expense{uuid = 12345,amount = 20000,
               tags = [one,three,undefined]}
      6> tuple:get(T,value).
      #expense{uuid = 12345,amount = 20000,
               tags = [one,three,undefined]}
      7> tuple:get(T,id).   
      #expense{uuid = 12345,amount = 20000,tags = [1,3,4]}
      8> tuple:stop().
      stop
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-08-03
        • 2020-08-20
        • 1970-01-01
        相关资源
        最近更新 更多