我正在寻求使用F#中的函数方法建模基于请求 - 响应的系统的最佳实践。
例如广义案例要求:
succeed
和failed
common
数据和specific
A / B / ...数据common
和specific
原因而被拒绝至于现在,我最终得到了以下设计:
type CommonData = {...}
type RequestMessage =
| ARequestMessage of CommonData * ARequestData
| BRequestMessage of CommonData * BRequestData
...
type Response<'S, 'F> =
| Success of 'S
| Failure of 'F
type ResponseMessage =
| AResponseMessage of Response<AResponseSuccess, AResponseFailure>
| BResponseMessage of Response<BResponseSuccess, BResponseFailure>
...
其中AResponseSuccess和BResponseSuccess包含相同的歧视联合案例或ResponseMessage
类型涵盖GeneralResponseMessage
类型
type GeneralResponseMessage =
| CommonFailure of CommonResponseFailure
| SpecificResponse of ResponseMessage
这两种情况看起来都很糟糕,我无法找到更清晰优雅的解决方案。
系统以状态机方式处理单个演进状态的请求,因此不可能将不同类型的请求处理分开
答案 0 :(得分:2)
这可能更适合https://codereview.stackexchange.com/,但让我试着在这里回答这个问题。
我对此的看法是垂直分组操作,而不是水平分组。我的意思是,不是将所有请求分为一种类型而将所有响应分组到另一种类型中,而是将相应的请求和响应类型配对,并为处理本身构建一个通用的包装器。
在您的情况下,处理从根本上是类型RequestMessage -> GeneralResponseMessage
的函数。我建议将其概括为以下内容:
type ProcessRequest<'requestData, 'responseMessage, 'responseFailure> =
CommonData -> 'requestData ->
Result<'responseMessage, ErrorResponse<'responseFailure>>
and ErrorResponse<'responseFailure> =
| CommonFailure of CommonResponseFailure
| SpecificResponse of 'responseFailure
请注意,我使用Result
中的FSharp.Core
代替Response
类型,因为他们对完全相同的内容进行了建模。
然后您可以创建特定的实例,例如
type AProcessRequest =
ProcessRequest<ARequestMessage, AResponseMessage, AResponseFailure>
然后可以使用它来处理特定的消息。在您的情况下,处理逻辑必须匹配RequestMessage
情况并继续进行,在我的情况下,您必须在调用特定处理器之前进行此匹配,但如果您需要将其分组为一种类型,则可以总是做一些事情来将所有实现作为单个数据提供
type ProcessMessage =
{ A : AProcessRequest
B : BProcessRequest
C : ... }
您可以在组合根目录中提供实现。
如果您不喜欢这么多特定类型,则不必为通用处理器的具体实例指定名称,C : ProcessMessage<CRequestMessage, CResponseMessage, CResponseFailure>
会很好,但如果有很多,可能会更不易读相似类型的实例。