登录功能还是使用功能? [英] Log in function or function using it?
问题描述
是否是 best (我知道没有灵丹妙药,但是使用一个优于另一个可能会有一些好处)-登录调用函数,或者调用函数它吗?
Is it best (I'm aware of that there's no silver bullet, but there may be some advantage by using one over the other) - to log in the calling function, or the function calling it?
示例:
方法1
module MongoDb =
let tryGetServer connectionString =
try
let server = new MongoClient(connectionString).GetServer()
server.Ping()
Some server
with _ -> None
用法:
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 ...
方法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
用法:
match MongoDb.tryGetServerLogable Config.connectionString logger with
| None ->
// ... code ...
| Some srv ->
// ... code ...
推荐答案
方法2 更好.通常,日志记录是一个跨领域关注点,因此最好将它与实现细节分开.最好通过组合"解决交叉切割问题;在OOD中,这可以通过装饰器或拦截器完成.在FP中,有时我们可以从OOD中学习,因为许多
Approach 2 is better. In general, logging is a Cross-Cutting Concern, so it's best decoupled from implementation details. Cross-Cutting Concerns are best addressed via Composition; in OOD, this can be done with Decorators or Interceptors. In FP, we can sometimes learn from OOD, because many of the principles translate from objects to closures.
但是,我宁愿使用像这样的东西:
However, instead of using Approach 2 above verbatim, I'd rather prefer something like this:
module MongoDb =
let tryGetServer connectionString =
try
let server = MongoClient(connectionString).GetServer()
server.Ping()
Some server
with _ -> None
请注意,MongoDb
模块不了解日志记录.这遵循单一责任原则,在函数式编程中也很重要.
Notice that the MongoDb
module has no knowledge of logging. This follows the Single Responsibility Principle, which is also valuable in Functional Programming.
tryGetServer
函数具有以下签名:
string -> MongoServer option
现在,您可以定义一个与MongoDb
模块完全脱钩的日志记录功能:
Now you can define a logging function, totally decoupled from the MongoDb
module:
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
在这里,您可以想象XyzLog
是使用Serilog,Log4Net,NLog,您自己的自定义日志记录框架或类似文件的特定日志记录模块的占位符.
Here, you can imagine that XyzLog
is a placeholder for a particular logging module, utilising Serilog, Log4Net, NLog, your own custom logging framework, or similar...
f
参数是具有通用签名'a -> 'b option
的函数,其中MongoDb.tryGetServer
是特化的.
The f
argument is a function with the generic signature 'a -> 'b option
, of which MongoDb.tryGetServer
is a specialization.
这意味着您现在可以像这样定义部分应用的功能:
This means that you can now define a partially applied function like this:
let tgs = XyzLog.tryGetServer MongoDb.tryGetServer (XyzLog.Logger())
函数tgs
还具有签名
string -> MongoServer option
因此,任何依赖具有此签名的功能的客户端都可以在不知道其区别的情况下互换使用MongoDb.tryGetServer
或tgs
.
So any client that depends on a function with this signature can use MongoDb.tryGetServer
or tgs
interchangeably, without knowing the difference.
这使您能够改变主意或相互独立重构MongoDb.tryGetServer
和日志记录基础结构.
This enables you to change you mind or refactor both MongoDb.tryGetServer
and your logging infrastructure independently of each other.
这篇关于登录功能还是使用功能?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!