同一erlang记录的不同视图
假设我有记录同一erlang记录的不同视图,erlang,Erlang,假设我有记录 -record(expense, {uuid, amount, tags}). 我想要一个可显示版本的记录。标记字段包含标记唯一ID。我想在表单上显示标签的名称,而不是唯一的ID。在Erlang你会怎么做?通常,在OOP语言中,您可以使用ViewModel来显示同一对象的不同版本 备选方案1 使用不同数据格式的相同记录,但我认为这会破坏接口合同;人们将无法知道自己拥有的记录的版本 选择2 创建另一个记录 -record(expense_view1, {uuid, amount,
-record(expense, {uuid, amount, tags}).
我想要一个可显示版本的记录。标记字段包含标记唯一ID。我想在表单上显示标签的名称,而不是唯一的ID。在Erlang你会怎么做?通常,在OOP语言中,您可以使用ViewModel来显示同一对象的不同版本
备选方案1
使用不同数据格式的相同记录,但我认为这会破坏接口合同;人们将无法知道自己拥有的记录的版本
选择2
创建另一个记录
-record(expense_view1, {uuid, amount, tags}).
但它会创建大量重复记录
选择3
使用元组或映射。如果我向记录中添加更多字段,Tuple很难维护,而maps也不能保证字段名的安全
标记字段包含标记唯一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
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"}}}
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
我想要一个可显示版本的记录。
但它会创建大量重复记录
是的,但在面向对象编程中,视图对象不是越来越多,它们包含模型对象中的全部或一个子集数据吗
选项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).
在外壳中:
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
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"}}}
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
您可以在访问功能中选择查看模式:
-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.
在外壳中给出:
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
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"}}}
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