Scala:通过阅读器进行的依赖注入和兼容性

时间:2019-04-03 07:23:16

标签: scala oop dependency-injection functional-programming reader-monad

当我们通过Reader实现DI时,我们将依赖项作为方法签名的一部分。假设我们有(没有实现):

trait Service1 { def f1:Int = ??? }
trait Service2 { def f2:Reader[Service1, Int] = ??? }

type Env= (Service1, Service2)
def c:Reader[Env, Int] = ???  //use Service2.f2 here

现在,f2需要额外的服务来实施,例如:

trait Service3
type Service2Env = (Service1, Service3)
//new dependecies on both:
trait Service2 { def f2:Reader[Service2Env, Int] = ??? }

它将破坏现有的客户端,如果不另外提供Service2.f2,他们将无法再使用Service3

对于OOP中常见的通过注入(通过构造函数或设置器)进行DI的情况,我只能将c作为Service2的依赖项。我不在乎它是如何构造的以及它的依赖项列表是什么。从这一点出发,Service2中的任何新依赖项都将保持c函数的签名不变。

如何以FP方式解决?有选择吗?有没有办法注入新的依赖关系,但是以某种方式保护客户免受更改的影响?

1 个答案:

答案 0 :(得分:2)

  

有没有办法注入新的依赖关系,但是以某种方式保护客户免受更改的影响?

这将达到目的,因为使用Reader(或使用Final Tagless或ZIO环境)是一种在每个函数的类型签名中显式声明(直接和间接)依赖项的方法。您这样做是为了跟踪代码中这些依赖关系的使用位置-仅通过查看函数签名,您就可以知道该代码是否可能产生巨大的副作用,例如发送电子邮件(或者也许是您出于其他原因执行此操作,但结果相同)。

您可能希望将其与构造函数注入混合匹配,以实现不需要那种静态检查级别的依赖项/效果。