gpt4 book ai didi

scala - 如何使用 Kleisli 实现缓存

转载 作者:行者123 更新时间:2023-12-02 04:33:21 25 4
gpt4 key购买 nike

我遵循了函数式和响应式(Reactive)建模一书中的设计原则。

因此所有服务方法都返回Kleisli

问题是如何在这些服务上添加可更新缓存

这是我当前的实现,是否有更好的方法(现有的组合器,更实用的方法,...)?

import scala.concurrent.duration.Duration
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.{Await, Future}
import scalaz.Kleisli

trait Repository {
def all : Future[Seq[String]]
def replaceAll(l: Seq[String]) : Future[Unit]
}

trait Service {
def all = Kleisli[Future, Repository, Seq[String]] { _.all }
def replaceAll(l: Seq[String]) = Kleisli[Future, Repository, Unit] { _.replaceAll(l) }
}

trait CacheService extends Service {
var cache : Seq[String] = Seq.empty[String]

override def all = Kleisli[Future, Repository, Seq[String]] { repo: Repository =>
if (cache.isEmpty) {
val fcache = repo.all
fcache.foreach(cache = _)
fcache
}
else
Future.successful(cache)
}

override def replaceAll(l: Seq[String]) = Kleisli[Future, Repository, Unit] { repo: Repository =>
cache = l
repo.replaceAll(l)
}
}

object CacheTest extends App {
val repo = new Repository {
override def replaceAll(l: Seq[String]): Future[Unit] = Future.successful()
override def all: Future[Seq[String]] = Future.successful(Seq("1","2","3"))
}
val service = new CacheService {}

println(Await.result(service.all(repo), Duration.Inf))
Await.result(service.replaceAll(List("a"))(repo), Duration.Inf)
println(Await.result(service.all(repo), Duration.Inf))
}

[更新]关于@timotyperigo的评论,我已经在存储库级别实现了缓存

class CachedTipRepository(val self:TipRepository) extends TipRepository {
var cache: Seq[Tip] = Seq.empty[Tip]

override def all: Future[Seq[Tip]] = …

override def replace(tips: String): Unit = …
}

我仍然有兴趣获得反馈以改进设计。

最佳答案

蒂莫西是完全正确的:缓存是存储库(而不是服务)的实现功能。实现功能/细节不应在契约(Contract)中公开,此时您的设计做得很好(但不是您的实现!)

深入挖掘你的设计问题,看看如何在 Scala 中完成依赖注入(inject)是很有趣的:

  1. 构造函数注入(inject)
  2. 蛋糕图案
  3. 阅读器单子(monad)

蛋糕模式和构造函数注入(inject)有一个相似之处:依赖关系在创建时绑定(bind)。使用 Reader monad(Kleisli 只是在其之上提供了一个附加层),您延迟绑定(bind),这会导致更多的可组合性(由于组合器)、更多的可测试性和更大的灵 active

如果通过添加缓存功能来装饰现有的 TipRepository,则可能不需要 Kleisli 的好处,它们甚至可能使代码更难以阅读。使用构造函数注入(inject)似乎是合适的,因为它是让您“做得好”的最简单模式

关于scala - 如何使用 Kleisli 实现缓存,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36461840/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com