Scala中依赖注入的读者组成
这是一个简单的服务示例,其方法返回读者:
trait Service1_1{ def s1f1:Reader[Map[String,Int],Int] = Reader(_("name")) def s1f2:Reader[Map[String,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]] = Reader(s => Reader(map => { val r = for { r1 <- s.s1f1 r2 <- s.s1f2 } yield r1 + r2 r.run(map) + i })) 问题是,有更好的方法吗?或至少语法?有几个级别的依赖,它会看起来很奇怪. 解决方法
我可能会“解开”读者,所以我没有两个(或更多)读者层,而是有一个n元组作为环境.然后,您可以将较小的读者“提升”到当前的当前级别.
例如,我使用Reader [(Service1_1,Map [String,Int]),Int]代替Reader [Service1_1,Reader [Map [String,Int]]: import cats.data.Reader trait Service1_1{ def s1f1: Reader[Map[String,Int] = Reader(_("name")) def s1f2: Reader[Map[String,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,"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. 这种方法的优点在于,即使您添加图层,也可以通过本地编写单个for-comprehension中的新读者和以前的读者. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |