首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何用Kleisli实现缓存

如何用Kleisli实现缓存
EN

Stack Overflow用户
提问于 2016-04-06 20:36:56
回答 1查看 229关注 0票数 5

我遵循了“功能和反应建模”()一书的设计原则。

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

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

这是我目前的实现,有没有更好的方法(现有的组合器,更多的功能方法,…)??

代码语言:javascript
复制
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注释的更新,我已经在存储库级别实现了缓存

代码语言:javascript
复制
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 = …
}

我仍然对改进设计的反馈感兴趣。

EN

回答 1

Stack Overflow用户

发布于 2017-07-07 18:02:33

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

深入了解您的设计问题,您很感兴趣的是如何在Scala中完成依赖项注入:

  1. 构造器注入
  2. 蛋糕图案
  3. 读者单读

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

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

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/36461840

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档