它是最好的(我知道没有银弹,但通过使用一个可能有一些优势) - 登录调用函数,或调用它的函数?
例子:
方法1
module MongoDb =
let tryGetServer connectionString =
try
let server = new MongoClient(connectionString).GetServer()
server.Ping()
Some server
with _ -> None
Run Code Online (Sandbox Code Playgroud)
用法:
match MongoDb.tryGetServer Config.connectionString with
| None ->
logger.Information "Unable to connect to the database server."
// ... code ...
| Some srv ->
logger.Information "Successfully connected to the database server."
// ... code ...
Run Code Online (Sandbox Code Playgroud)
方法2
module MongoDb =
let tryGetServer connectionString =
try
let server = new MongoClient(connectionString).GetServer()
server.Ping()
Some server
with _ -> None
let tryGetServerLogable connectionString logger =
match tryGetServer connectionString with
| None ->
logger.Information "Unable to connect to the database server."
None
| Some srv ->
logger.Information "Successfully connected to the database server."
Some srv
Run Code Online (Sandbox Code Playgroud)
用法:
match MongoDb.tryGetServerLogable Config.connectionString logger with
| None ->
// ... code ...
| Some srv ->
// ... code ...
Run Code Online (Sandbox Code Playgroud)
方法2更好.一般来说,日志记录是一个跨领域的关注点,所以它最好与实现细节分离.交叉问题最好通过作文来解决; 在OOD中,这可以通过装饰器或拦截器来完成.在FP中,我们有时可以从OOD中学习,因为许多原则都是从对象转换为闭包.
但是,我不想逐字逐句使用方法2,而是更喜欢这样的东西:
module MongoDb =
let tryGetServer connectionString =
try
let server = MongoClient(connectionString).GetServer()
server.Ping()
Some server
with _ -> None
Run Code Online (Sandbox Code Playgroud)
请注意,该MongoDb模块不了解日志记录.这遵循单一责任原则,这在功能编程中也很有价值.
该tryGetServer功能有这个签名:
string -> MongoServer option
Run Code Online (Sandbox Code Playgroud)
现在您可以定义一个完全与MongoDb模块分离的日志记录功能:
module XyzLog =
type Logger() =
member this.Information message = ()
let tryGetServer f (logger : Logger) connectionString =
match f connectionString with
| None ->
logger.Information "Unable to connect to the database server."
None
| Some srv ->
logger.Information "Successfully connected to the database server."
Some srv
Run Code Online (Sandbox Code Playgroud)
在这里,您可以想象这XyzLog是一个特定日志记录模块的占位符,使用Serilog,Log4Net,NLog,您自己的自定义日志记录框架或类似的...
该f参数是与通用签名的功能'a -> 'b option,它的MongoDb.tryGetServer是一个特例.
这意味着您现在可以像这样定义部分应用的函数:
let tgs = XyzLog.tryGetServer MongoDb.tryGetServer (XyzLog.Logger())
Run Code Online (Sandbox Code Playgroud)
该功能tgs 还具有签名
string -> MongoServer option
Run Code Online (Sandbox Code Playgroud)
因此,依赖于具有此签名的函数的任何客户端都可以使用MongoDb.tryGetServer或tgs互换,而不需要知道差异.
这使您可以MongoDb.tryGetServer相互独立地改变您的想法或重构您的日志记录基础结构.