Scala:通过 Reader 和兼容性进行依赖注入

Scala: Dependency Injection via Reader and compatibility

当我们通过 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

通过注入(通过构造函数或设置器)使用 DI,这在 OOP 中很常见,我只会将 c 用作 Service2 的依赖项。它是如何构造的,它的依赖列表是什么,我不在乎。从这一点开始,Service2 中的任何新依赖项都将保持 c 函数的签名不变。

FP方式是怎么解决的?有选择吗?有没有一种方法可以注入新的依赖项,但又能以某种方式保护客户免受更改的影响?

Is there a way to inject new dependencies, but somehow protect customers from the change?

这有点违背了目的,因为使用 Reader(或者 Final Tagless 或 ZIO Environment)是一种在每个函数的类型签名中显式声明(直接和间接)依赖关系的方法。您这样做是为了能够跟踪在您的代码中使用这些依赖项的位置——只需查看函数签名,您就可以判断此代码​​是否可能具有显着的副作用,例如发送电子邮件(或者可能你这样做是出于其他原因,但结果是一样的)。

您可能希望将此与不需要该级别静态检查的 dependencies/effects 的构造函数注入混合搭配。