Tampilan berbeda untuk rekaman erlang yang sama

Misalkan saya punya catatan

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

Saya ingin memiliki versi rekaman yang dapat ditampilkan. Bidang tag berisi id unik tag. Saya ingin menampilkan nama tag pada formulir, bukan id unik. Bagaimana Anda melakukannya di Erlang? Biasanya, dalam bahasa OOP, Anda akan melakukan ViewModel untuk memiliki versi berbeda yang dapat ditampilkan dari objek yang sama.

Pilihan 1 Gunakan catatan yang sama dengan format data yang berbeda tapi saya pikir itu akan merusak kontrak antarmuka; seseorang tidak akan dapat mengetahui versi rekaman mana yang dimilikinya.

Opsi 2 Buat catatan lain

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

Tapi itu akan membuat banyak catatan duplikat.

Opsi 3 Gunakan tuple atau peta. Tuple sulit dipertahankan jika saya menambahkan lebih banyak bidang ke catatan, dan peta tidak menjamin keamanan nama bidang.


person user2187032    schedule 15.02.2021    source sumber


Jawaban (2)


Bidang tag berisi id unik tag. Saya ingin menampilkan nama tag pada formulir, bukan id unik.

Bagaimana dengan ini:

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

Di dalam cangkang:

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

Saya ingin memiliki versi rekaman yang dapat ditampilkan. Tapi itu akan membuat banyak catatan duplikat.

Ya, tapi di OOP bukankah Anda memiliki proliferasi objek View yang berisi semua atau sebagian data di objek Model?

Pilihan 1 Gunakan catatan yang sama dengan format data yang berbeda tapi saya pikir itu akan merusak kontrak antarmuka; seseorang tidak akan dapat mengetahui versi rekaman mana yang dimilikinya.

Anda dapat menyusun catatan untuk menyisakan tempat kosong untuk nama tag yang sesuai dengan id tag, lalu mengisi nama tag bila Anda dapat:

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

Di dalam cangkang:

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"}}}
person 7stud    schedule 15.02.2021

Anda dapat memilih mode tampilan di fungsi akses:

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

yang memberi di 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
person Pascal    schedule 16.02.2021