当我们通过阅读器实现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 通过注入(通过构造函数或 setter(,这在 OOP 中很常见,我将仅用作c
Service2
的依赖项。它是如何构造的,它的依赖项列表是什么,我不在乎。从这一点开始,Service2
中的任何新依赖项都将保持c
函数的签名不变。
如何以FP方式解决?有选择吗?有没有办法注入新的依赖项,但以某种方式保护客户免受更改的影响?
有没有办法注入新的依赖项,但以某种方式保护客户免受更改的影响?
这会有点违背目的,因为使用 Reader(或者最终无标签或 ZIO 环境(是一种在每个函数的类型签名中显式声明(直接和间接(依赖关系的方法。您这样做是为了能够跟踪这些依赖项在代码中的使用位置 - 只需查看函数签名,您就可以判断此代码是否可能产生显着的副作用,例如发送电子邮件(或者您可能出于其他原因这样做,但结果是相同的(。
您可能希望将其与构造函数注入混合搭配,用于不需要该级别的静态检查的依赖项/效果。