[英]How to avoid dependency injection in Scala?
I read Dependency Injection Without the Gymnastics PDF which indicates there's no need for any fancy DI framework, but it's beyond my grasp (at least without concrete examples). 我阅读了没有体操PDF的依赖注入,这表明不需要任何花哨的DI框架,但它超出了我的掌握(至少没有具体的例子)。 I'll try watching Dependency Injection Without the Gymnastics and Dead Simple Dependency Injection when I have a chance.
当我有机会时,我会尝试在没有体操和死亡简单依赖注入的情况下观察依赖注入 。
Using Guice in Java, if A depends on both B and C and both B and C depend on D, one would have something like: 在Java中使用Guice,如果A依赖于B和C并且B和C都依赖于D,那么就会有:
public class A {
@Inject
public A(B b, C c) {
this.b = b;
this.c = c;
}
}
public class B {
@Inject
public B(D d) {
this.d = d;
}
}
public class C {
@Inject
public C(D d) {
this.d = d;
}
}
public class D { /* ... */ }
and a module that says which implementation of D to use, then one would just ask for an instance of A from the injector: 以及一个模块,说明要使用哪个D实现,然后只需要从进样器中请求A的实例:
A a = injector.createInstance(A.class);
Given what's presented in the URLs above, how would the Scala-equivalent of the above code look? 鉴于上面的URL中显示的内容,上述代码的Scala等价物如何?
FWIW, I'm also investigating https://github.com/dickwall/subcut/blob/master/GettingStarted.md and am simply trying to understand the anti-DI solution. FWIW,我也正在调查https://github.com/dickwall/subcut/blob/master/GettingStarted.md ,我只是想了解反DI解决方案。
Implicit parameters are completely sufficient for the use case you're describing. 对于您正在描述的用例, 隐式参数完全足够。
case class A(implicit b: B, c: C)
case class B(implicit d: D)
case class C(implicit d: D)
class D { /* ... */ }
implicit val theD = new D
implicit val theB = B()
implicit val theC = C()
Now you can ask for an A
just by: 现在你可以通过以下方式要求
A
:
val a = A()
You may solve it with self-types . 你可以用自我类型来解决它。
A depends on both B and C and both B and C depend on D
A取决于B和C,B和C都取决于D.
so one could write this like that: 所以可以这样写:
class A {
self: B with C =>
}
trait B {
self: D =>
}
trait C {
self: D =>
}
trait D {}
and then on a call side: 然后在通话方面:
val x = new A with BImpl with CImpl with DImpl
but code below won't compile, because dependencies on B,C,D classes not resolved: 但是下面的代码将无法编译,因为B,C,D类的依赖关系未得到解决:
val x = new A
It's tricky to provide that type of dependency injection. 提供这种类型的依赖注入很棘手。 Most of the above examples require you to create the implicits near where the classes are instantiated.
上面的大多数示例都要求您在实例化类的位置附近创建implicits。
Closest I could come up with is: 我能想到的最近的是:
class A(implicit b:B, c:C)
class B(implicit d:D)
class C(implicit d:D)
trait D { //the interface
def x:Unit
}
object Implicits {
implicit def aFactory:A = new A
implicit lazy val bInstance:B = new B
implicit def cFactory:C = new C
implicit def dFactory:D = new D {
def x:Unit = {/* some code */}
}
}
And then in your code you use it like this: 然后在你的代码中你使用它像这样:
import Implicits._
object MyApplication {
def main(args: Array[String]):Unit = {
val a = new A
}
}
If you need to be able to specify different versions when you (for example) are testing, you could do something like this: 如果您(例如)在测试时需要能够指定不同的版本,则可以执行以下操作:
import Implicits._
object MyApplication {
// Define the actual implicits
Implicits.module = new Module {
import Implicits._
def a = new A
lazy val b = new B
def c = new C
def d = new D {
def x = println("x")
}
}
def main(args: Array[String]):Unit = {
val a = new A // or val a = implicitly[A]
}
}
// The contract (all elements that you need)
trait Module {
def a: A
def b: B
def c: C
def d: D
}
// Making the contract available as implicits
object Implicits {
var module: Module = _
implicit def aFactory:A = module.a
implicit def bFactory:B = module.b
implicit def cFactory:C = module.c
implicit def dFactory:D = module.d
}
This would allow you to simply import Implicits._ in any file and would provide a similar workflow as the one in the original question. 这将允许您在任何文件中简单地导入Implicits._,并提供与原始问题中的工作流程类似的工作流程。
In most cases however I would not use this tactic. 但在大多数情况下,我不会使用这种策略。 I would simply make the implicit available in classes that create instances:
我只是在创建实例的类中使隐式可用:
object MyApplication {
implicit def a: A = new A
implicit lazy val b: B = new B
implicit def c: C = new C
implicit def d: D = new D {
def x: Unit = println("x")
}
def main(args: Array[String]): Unit = {
val a = implicitly[A]
val e = new E
}
}
class E(implicit d:D) {
new C
}
Here E
is defined in another file and creates an instance of C
. 这里
E
在另一个文件中定义并创建一个C
实例。 We require D
to be passed to E
and with that document that E
depends on D
(via C
). 我们要求
D
被传递给E
,并且该文件E
依赖于D
(通过C
)。
I think @om-nom-nom's answer is quite close to what you want. 我认为@ om-nom-nom的答案非常接近你想要的。 Here is what I've got:
这是我得到的:
class A {
self: B with C =>
def sum = tripleD + doubleD
}
trait B {
self: D =>
def tripleD = x * 3
}
trait C {
self: D =>
def doubleD = x * 2
}
trait D extends B with C {
val x: Int
}
trait E extends D {
val x = 3
}
trait F extends D {
val x = 4
}
val a = new A with E
val b = new A with F
println("a.sum = " + a.sum)
println("b.sum = " + b.sum)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.