I followed the design principle from the book Functional and Reactive Modeling.
So, all service methods return Kleisli .
The question is how can I add an updated cache for these services.
Here is my current implementation, is there a better way (existing combinators, a more functional approach, ...)?
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)) }
[update] Regarding the comment by @timotyperigo, I implement repository-level caching
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 = β¦ }
I'm interested in feedback to improve the design.
source share