scala - 将 OOP "decorator"重构为释放 monad 结构

标签 scala functional-programming scala-cats free-monad

我有一些“遗留”Scala 代码(类 Java),它执行一些数据访问。有一个装饰器可以跟踪 DAO 方法(收集指标)的使用情况,如下所示:

class TrackingDao(tracker: Tracker) extends Dao {
    def fetchById(id: UUID, source: String): Option[String] = {
        tracker.track("fetchById", source) {
            actualFetchLogic(...)
        }
    }
    ...
}

我正在尝试将其建模为一个 Free monad。我为 DAO 操作定义了以下代数:

sealed trait DBOp[A]
case class FetchById(id: UUID) extends DBOp[Option[String]]
...

我看到两个选项:

a) 我可以制作两个采用DBOp 的解释器,一个执行实际的数据访问,另一个执行跟踪,然后将它们组合在一起或者
b) 我使 Tracking 成为显式代数,并使用 Coproduct 在相同的 for 组合中使用它们,或者
c) 完全不同的东西!

第一个选项看起来更像是一种“装饰器”方法,它与 DBOp 相关联,第二个是更通用的解决方案,但需要显式调用“跟踪”代数。

此外,请注意原始 fetchById 调用中的 source 参数:它仅用于跟踪。我宁愿将它从 API 中删除。

真正的问题是:如何为跟踪建模?

最佳答案

从你的问题中还不完全清楚,但如果跟踪是一种环境效应,当你执行数据库访问时应该“发生”并且 source 只是用于跟踪目的的参数,你可能不会必须用您的自由语言提及它。您可以使用您现在拥有的 ADT 并将其解释为 (Tracker, Source, OtherStuff) => IO[A] 例如,因此您得到的是一个函数,该函数将生成一个程序来执行 DB一旦你给它一个 Tracker 和源以及你需要的任何其他东西(例如数据库连接)就可以访问,并且跟踪实现对解释器来说是完全私有(private)的。这使您可以在编写数据库程序时完全不考虑跟踪。

另一方面,如果您确实需要讨论业务逻辑中的跟踪,那么我们可能需要更多关于拥有多个Trackersource 及其介绍和使用方式。可能需要副产品或扩展语言或嵌套语言来处理您需要表达的内容。

关于scala - 将 OOP "decorator"重构为释放 monad 结构,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42758278/

相关文章:

Scala - 迭代器和可迭代的惰性 - 内存消耗

java - 为什么 @RequestMapping 注解在 java 中接受 String 参数而在 scala 中不接受?

scala - Option[F[ShoppingCart]] 到 F[Option[ShoppingCart]] 之间的转换

scala - free monad 应该基于的仿函数在哪里

scala - 如何使用 http4s 将 cats IO 转换为 Effect

scala - 在 Scala 中,特征是否可以扩展需要参数的类?

scala - 无法在 Spark Sql 的 OutputMetrics 中获取 RecordsWritten

clojure - 翻转 "->"语句中的参数

haskell - 使用 zip 部分应用 <*>

groovy - 在不同的对象上调用闭包?