[英]Composition of Readers for Dependency Injection in Scala
这是一个简单的服务示例,其方法返回读者:
trait Service1_1{
def s1f1:Reader[Map[String,Int],Int] =
Reader(_("name"))
def s1f2:Reader[Map[String,Int],Int] =
Reader(_("age"))
}
这是一个服务使用者,它接受参数,map,并返回阅读器本身:
trait Service1_2 {
def s12f1(i:Int, map:Map[String,Int]):Reader[Service1_1, Int] =
Reader(s => {
val r = for {
r1 <- s.s1f1
r2 <- s.s1f2
} yield r1 + r2
r.run(map) + i
})
}
好的,要使用Service1_2.s12f1我必须在参数列表中有map:
object s1 extends Service1_1
object s2 extends Service1_2
val r = s2.s12f1(3, Map("age"-> 1, "name"-> 2)).run(s1)
问题:如何实现Service1_2.s12f2
:
trait Service1_2 {
def s2f2 = ???
}
为了能够运行它:
s2.s2f2(2)
.run(s1)
.run(Map("age"-> 1, "name"-> 2))
主要思想是推迟将依赖关系传递给执行。 这应该允许获得更好的组合和延迟执行。 如何让它工作? 如果存在具有此类依赖关系的嵌套调用,那么使用读者的最佳做法是什么? 例如,想象服务Service1_3
,它在一种方法中将同时使用Service1_2.s2f2
和Service1_1.s1f1
更新 ,好吧,我可以实现它,但它看起来,复杂:
def s2f2(i:Int): Reader[Service1_1, Reader[Map[String,Int],Int]] =
Reader(s => Reader(map => {
val r = for {
r1 <- s.s1f1
r2 <- s.s1f2
} yield r1 + r2
r.run(map) + i
}))
问题是,有更好的方法吗? 或至少语法? 有几个级别的依赖,它会看起来很奇怪。
我可能会“解开”读者,所以我没有两个(或更多)读者层,而是有一个n元组作为环境。 然后你就可以“养”小读者到当前的水平与local
。
例如,我使用Reader[(Service1_1, Map[String, Int]), Int]
代替Reader[Service1_1, Reader[Map[String, Int], Int]]
Reader[(Service1_1, Map[String, Int]), Int]
:
import cats.data.Reader
trait Service1_1{
def s1f1: Reader[Map[String, Int], Int] = Reader(_("name"))
def s1f2: Reader[Map[String, Int], Int] = Reader(_("age"))
}
trait Service1_2 {
type Env = (Service1_1, Map[String,Int])
def s2f2(i: Int): Reader[Env, Int] =
for {
s <- Reader((_: Env)._1)
r1 <- s.s1f1.local((_: Env)._2)
r2 <- s.s1f2.local((_: Env)._2)
} yield r1 + r2 + i
}
然后:
scala> object s1 extends Service1_1
defined object s1
scala> object s2 extends Service1_2
defined object s2
scala> s2.s2f2(2).run((s1, Map("age"-> 1, "name"-> 2)))
res0: cats.Id[Int] = 5
这与s2f2
完全相同,除了s2.s2f2(2).run(s1).run(myMap)
不是s2.s2f2(2).run((s1, myMap))
,甚至只是s2.s2f2(2).run(s1, myMap)
使用改编的args。
这种方法的优点是,即使在添加图层时,您也可以通过local
编写单个for
comprehension中的新读者和以前的读者。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.