step by step开发一个简易股票交易系统(四)---支持多股票

Step4:使用gen_server改写stock,增加stock_server,支持多只股票买卖,支持股票开牌/停牌,可以显示交易挂单
stock.erl
-module(stock).
-behaviour(gen_server).
-export([start/0,stop/0]).

-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).

-record(state, {}).

start()->gen_server:start_link({local,?MODULE},?MODULE,[],[]).
stop()->gen_server:call(?MODULE,stop). 
init([]) ->
    {ok, {[],[],1}}.

handle_call(stop,_From,L) ->  
    {stop,normal,stopped,L}.  

handle_cast({sell,{Price,Number,Name}},  {BuyL,SellL,TradeId}) ->
    case lookup(buy,{Price,none},BuyL) of
        {_,Price,0,none}->
            L2=add(sell,{TradeId,Price,Number,Name},SellL),
            gen_server:cast(stock_server,{ok,hangup}),
            {noreply,{BuyL,L2,TradeId+1}};
        {TradeId1,Price1,Number1,Buy}->
            if Number1=:=Number->
                   L2=remove({TradeId1,Price1,Number1,Buy},BuyL),
                   gen_server:cast(stock_server,{ok,Buy}),
                   {noreply,{L2,SellL,TradeId}};
               Number1<Number->
                   L2=remove({TradeId1,Price1,Number1,Buy},BuyL),
                   gen_server:cast(stock_server,{ok,Buy}),
                   handle_cast({sell,{Price,Number-Number1,Name}},{L2,SellL,TradeId});
               Number1>Number->
                   L2=[replace(X,{TradeId1,Price1,Number1,Buy},Number1-Number)||X<-BuyL],
                   gen_server:cast(stock_server,{ok,Buy}),
                   {noreply,{L2,SellL,TradeId}}
            end
    
    end;


handle_cast({buy,{Price,Number,Name}}, {BuyL,SellL,TradeId}) ->
    case lookup(sell,{Price,none},SellL) of
        {_,Price,0,none}->
            L2=add(buy,{TradeId,Price,Number,Name},BuyL),
            gen_server:cast(stock_server,{ok,hangup}),
            {noreply,{L2,SellL,TradeId+1}};
        {TradeId1,Price1,Number1,Sell}->
            if Number1=:=Number->
                   L2=remove({TradeId1,Price1,Number1,Sell},SellL),
                   gen_server:cast(stock_server,{ok,Sell}),
                   {noreply,{BuyL,L2,TradeId}};
               Number1<Number->
                   L2=remove({TradeId1,Price1,Number1,Sell},SellL),
                   gen_server:cast(stock_server,{ok,Sell}),
                   handle_cast({buy,{Price,Number-Number1,Name}},{BuyL,L2,TradeId});                          
               Number1>Number->
                   L2=[replace(X,{TradeId1,Price1,Number1,Sell},Number1-Number)||X<-SellL],
                   gen_server:cast(stock_server,{ok,Sell}),
                   {noreply,{BuyL,L2,TradeId}}
            end
    
    end;

handle_cast({list,Count}, {BuyL,SellL,TradeId}) ->
    X = getList(Count,BuyL),
    gen_server:cast(stock_server,{ok,{buy_list,X}}),
    Y = getList(Count,SellL),
    gen_server:cast(stock_server,{ok,{sell_list,Y}}),
    {noreply,{BuyL,SellL,TradeId}};

handle_cast(stop,State) ->
    {stop,normal,State};

handle_cast(_Msg, State) ->
    {noreply, State}.

handle_info(Info, State) ->
    {noreply, State}.

terminate(Reason, State) ->
    ok.

code_change(OldVsn, State, Extra) ->
    {ok, State}.

lookup(sell,{Price,Buy},[{TradeId,Price1,Number,Name}|_T]) ->
    if
        Price>=Price1 -> {TradeId,Price1,Number,Name};
        true->{0,Price,0,Buy}
    end;       

lookup(buy,{Price,Sell},[{TradeId,Price1,Number,Name}|_T]) ->
    if
        Price=<Price1 -> {TradeId,Price1,Number,Name};
        true->{0,Price,0,Sell}
    end;    
lookup(_,{Price,Name},[])->{0,Price,0,Name}.

add(sell,{TradeId,Price,Number,Name},[{TradeId1,Price1,Number1,Name1}|T]) ->
    if
        Price>=Price1 -> [{TradeId1,Price1,Number1,Name1}|add(sell,{TradeId,Price,Number,Name},T)];
        true->[{TradeId,Price,Number,Name}|[{TradeId1,Price1,Number1,Name1}|T]]
    end;       

add(buy,{TradeId,Price,Number,Name},[{TradeId1,Price1,Number1,Name1}|T]) ->
    if
        Price=<Price1 -> [{TradeId1,Price1,Number1,Name1}|add(buy,{TradeId,Price,Number,Name},T)];
        true->[{TradeId,Price,Number,Name}|[{TradeId1,Price1,Number1,Name1}|T]]
    end;       
add(_,{TradeId,Price,Number,Name},[])->[{TradeId,Price,Number,Name}].

remove(Trade,L)-> [X||X<-L,X/=Trade].

replace({TradeId,Price,Number,Name},{TradeId1,Price1,Number1,Name1},Number2)->
    if
        {TradeId1,Price1,Number1,Name1}=:={TradeId,Price,Number,Name}->
            {TradeId,Price,Number2,Name};
        true->{TradeId,Price,Number,Name}
    end.

getList(_,[])->[];
getList(0,_)->[];
getList(Count,[{_,Price,Number,Name}|T])->
    [{Price,Number,Name}|getList(Count-1,T)].

stock_server.erl
-module(stock_server).

-behaviour(gen_server).
-export([list/1, sell/2, buy/2, start/0,stop/0,start_trade/1,stop_trade/1]).
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).

-record(state, {}).

-import(stock,[start/1,stop/1]).
start()->gen_server:start_link({local,stock_server},stock_server,[],[]).
stop()->gen_server:cast(?MODULE,stop).
sell(Id,Trade)->gen_server:cast(?MODULE,{sell,Id,Trade}).
buy(Id,Trade)->gen_server:cast(?MODULE,{buy,Id,Trade}).
list(Id)->gen_server:cast(?MODULE,{list,Id}).
start_trade(Id)->gen_server:cast(?MODULE,{start_trade,Id}).
stop_trade(Id)->gen_server:cast(?MODULE,{stop_trade,Id}).

init([]) ->
    {ok, []}.

handle_call(Request, From, State) ->
    Reply = ok,
    {reply, Reply, State}.

handle_cast(stop,State) ->
    {stop,stopped,State};

handle_cast({start_trade,Id},State) ->
    case gen_server:start(stock,[],[]) of
        {ok,Pid}->put(Id,Pid);
        Any->
            io:format("start_trade error:~w~n",[Any])
    end,
    {noreply,  State};
handle_cast({stop_trade,Id},State) ->
    case get(Id) of
        undefined->
            io:format("stock Id=~w have not start trade~n",[Id]);
        Pid->
            gen_server:call(Pid,stop),
            erase(Id)
    
    end,
    {noreply, State};

handle_cast({list,Id}, State) ->
    case get(Id) of
        undefined->
            io:format("stock Id=~w have not start trade~n",[Id]);
        Pid->
            gen_server:cast(Pid,{list,5})
    end,
    {noreply,  State};

handle_cast({buy,Id,Trade}, State) ->
    case get(Id) of
        undefined->
            io:format("stock Id=~w have not start trade~n",[Id]);
        Pid->
            
            gen_server:cast(Pid,{buy,Trade})
    end,
    {noreply,  State};

handle_cast({sell,Id,Trade}, State) ->
    case get(Id) of
        undefined->
            io:format("stock Id=~w have not start trade~n",[Id]);
        Pid->
            
            gen_server:cast(Pid,{sell,Trade})
    end,
    {noreply,  State};

handle_cast({ok,Msg}, State) ->
    io:format("ok: ~w~n",[Msg]),
    {noreply, State};

handle_cast(_Msg, State) ->
    {noreply, State}.

handle_info(Info, State) ->
    {noreply, State}.

terminate(Reason, State) ->
    ok.
code_change(OldVsn, State, Extra) ->
    {ok, State}.

你可能感兴趣的:(erlang)