Scala:通过Reader实现依赖注入和兼容性

3

当我们通过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] = ??? }

它会破坏现有的客户端,他们不能再无需提供Service3的情况下使用Service2.f2

通过注入依赖项(通过构造函数或设置器),这在OOP中很常见,我只会将Service2作为c的依赖项。如何构建它以及其依赖项列表,我不关心。从这一点出发,Service2中的任何新依赖都将保持c函数签名不变。

在FP方式中如何解决?是否有选项?是否有一种方法可以注入新的依赖项,但又能以某种方式保护客户免受更改的影响?


2
"这将会破坏现有的客户端。也许我理解有误,但如果您向该方法添加一个额外的参数,这也会在面向对象编程中出现问题,因为您将无法再不提供参数的情况下调用该方法。" - Yuval Itzchakov
1
就像@YuvalItzchakov所说,如果您想要摆脱所有(对象实例)状态(甚至是“良性”的不可变构造函数注入的依赖项),那么所有函数的依赖项都必须成为参数,并且这些参数必须由调用者提供。没有其他办法。 - Thilo
1个回答

3
有没有一种方法可以注入新的依赖项,但同时保护客户免受更改的影响?
这样做有点违背初衷,因为使用Reader(或者Final Tagless或ZIO环境)是一种在每个函数的类型签名中明确声明(直接和间接)依赖项的方式。你这样做是为了能够跟踪在代码中使用这些依赖项的位置——只要看一个函数的签名,就可以判断这段代码是否可能产生重大副作用,例如发送电子邮件(也许你还有其他原因,但结果是一样的)。
您可能希望将其与构造函数注入混合使用,以获取不需要该级别静态检查的依赖项/效果。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接