在函数调用中隐藏状态
Hide state in function call
我考虑在函数调用中隐藏状态。
示例:
body_to_client(Req, ClientRef) ->
case cowboy_req:body(Req) of
{ok, Data, Req2} ->
ok = hackney:send_body(ClientRef, Data),
Req2;
{more, Data, Req2} ->
ok = hackney:send_body(ClientRef, Data),
body_to_client(Req2, ClientRef)
end.
但我想将这段代码分成几个部分并隐藏实现:
body_to_client(ReadRequestBody, ClientRef) ->
case ReadRequestBody() of
{ok, Data} ->
ok = hackney:send_body(ClientRef, Data),
ReadRequestBody;
{more, Data} ->
ok = hackney:send_body(ClientRef, Data),
body_to_client(ReadRequestBody, ClientRef)
end.
其中 ReadRequestBody 是一个包含所有详细信息和状态的函数。
我认为应该是这样的:
ReadRequestBody = fun() ->
{Status, Data, Req2} = cowboy_req:body(Req),
{Status, Data}
end
但我不知道如何处理 Req2 并在下次调用时传递它。
提取 Req2 的唯一方法是 return 它与 ReadRequestBody
的其余结果:
ReadRequestBody = fun() ->
{Status, Data, Req2} = cowboy_req:body(Req),
{{Status, Data}, Req2}
end
然后你必须检查,就像你以前做的一样,但现在有更多的语法,一个你不需要的闭包和更多的行来分割结果和匹配它的内容,等等。头发着火了!啊!让我们把音量调低一点...
我觉得这整件事变得过于复杂了,所以也许转向另一个方向,删除智能设备而不是添加它们,揭示了一些东西。让我们看看没有 case
:
的样子
body_to_client({ok, Data, Req}, ClientRef) ->
ok = hackney:send_body(ClientRef, Data),
Req;
body_to_client({more, Data, Req}, ClientRef) ->
ok = hackney:send_body(ClientRef, Data),
body_to_client(cowboy_req:body(Req), ClientRef).
现在 body_to_client/2
是一个独立的命名案例。但是我们两次都在做同样的事情(总是将数据发送到 ClientRef),写两次感觉很傻。关于是否迭代,实际上只有一个决定点。让我们提炼出来:
body_to_client({Status, Data, Req}, ClientRef) ->
ok = hackney:send_body(ClientRef, Data),
check_status({Status, Req} ClientRef).
check_status({ok, Req}, _) ->
Req;
check_status({more, Req}, ClientRef) ->
body_to_client(cowboy_req:body(Req), ClientRef).
现在一切都已命名,代码明确说明了每一部分的作用。如果 check_status/2
看起来更易读,我们可以将 check_status/2
作为 case
带回 body_to_client/2
中:
body_to_client({Status, Data, Req}, ClientRef) ->
ok = hackney:send_body(ClientRef, Data),
case Status of
ok -> Req;
more -> body_to_client(cowboy_req:body(Req), ClientRef)
end.
请注意,将作为命名函数正常工作的匹配项作为 case
引入另一个函数有些争议。 body_to_client
这个名字现在是一个小谎言,因为这个函数不仅仅是将正文发送给客户端(但这个谎言的性质可能重要也可能无关紧要,具体取决于代码的其余部分)。
我考虑在函数调用中隐藏状态。 示例:
body_to_client(Req, ClientRef) ->
case cowboy_req:body(Req) of
{ok, Data, Req2} ->
ok = hackney:send_body(ClientRef, Data),
Req2;
{more, Data, Req2} ->
ok = hackney:send_body(ClientRef, Data),
body_to_client(Req2, ClientRef)
end.
但我想将这段代码分成几个部分并隐藏实现:
body_to_client(ReadRequestBody, ClientRef) ->
case ReadRequestBody() of
{ok, Data} ->
ok = hackney:send_body(ClientRef, Data),
ReadRequestBody;
{more, Data} ->
ok = hackney:send_body(ClientRef, Data),
body_to_client(ReadRequestBody, ClientRef)
end.
其中 ReadRequestBody 是一个包含所有详细信息和状态的函数。 我认为应该是这样的:
ReadRequestBody = fun() ->
{Status, Data, Req2} = cowboy_req:body(Req),
{Status, Data}
end
但我不知道如何处理 Req2 并在下次调用时传递它。
提取 Req2 的唯一方法是 return 它与 ReadRequestBody
的其余结果:
ReadRequestBody = fun() ->
{Status, Data, Req2} = cowboy_req:body(Req),
{{Status, Data}, Req2}
end
然后你必须检查,就像你以前做的一样,但现在有更多的语法,一个你不需要的闭包和更多的行来分割结果和匹配它的内容,等等。头发着火了!啊!让我们把音量调低一点...
我觉得这整件事变得过于复杂了,所以也许转向另一个方向,删除智能设备而不是添加它们,揭示了一些东西。让我们看看没有 case
:
body_to_client({ok, Data, Req}, ClientRef) ->
ok = hackney:send_body(ClientRef, Data),
Req;
body_to_client({more, Data, Req}, ClientRef) ->
ok = hackney:send_body(ClientRef, Data),
body_to_client(cowboy_req:body(Req), ClientRef).
现在 body_to_client/2
是一个独立的命名案例。但是我们两次都在做同样的事情(总是将数据发送到 ClientRef),写两次感觉很傻。关于是否迭代,实际上只有一个决定点。让我们提炼出来:
body_to_client({Status, Data, Req}, ClientRef) ->
ok = hackney:send_body(ClientRef, Data),
check_status({Status, Req} ClientRef).
check_status({ok, Req}, _) ->
Req;
check_status({more, Req}, ClientRef) ->
body_to_client(cowboy_req:body(Req), ClientRef).
现在一切都已命名,代码明确说明了每一部分的作用。如果 check_status/2
看起来更易读,我们可以将 check_status/2
作为 case
带回 body_to_client/2
中:
body_to_client({Status, Data, Req}, ClientRef) ->
ok = hackney:send_body(ClientRef, Data),
case Status of
ok -> Req;
more -> body_to_client(cowboy_req:body(Req), ClientRef)
end.
请注意,将作为命名函数正常工作的匹配项作为 case
引入另一个函数有些争议。 body_to_client
这个名字现在是一个小谎言,因为这个函数不仅仅是将正文发送给客户端(但这个谎言的性质可能重要也可能无关紧要,具体取决于代码的其余部分)。