使用它登录功能或功能?

ebb*_*ebb 4 f#

它是最好的(我知道没有银弹,但通过使用一个可能有一些优势) - 登录调用函数,或调用它的函数?

例子:

方法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)

Mar*_*ann 5

方法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.tryGetServertgs互换,而不需要知道差异.

这使您可以MongoDb.tryGetServer相互独立地改变您的想法或重构您的日志记录基础结构.

  • 另请参阅FsharForFunAndProfit.com(http://fsharpforfunandprofit.com/posts/recipe-part2/)中的"铁路导向编程",了解一般实现模式. (4认同)