5

私はDependency Injection Without the Gymnastics PDFを読みましたが、これは派手な DI フレームワークは必要ないことを示していますが、それは私の理解を超えています (少なくとも具体的な例はありません)。機会があれば、体操のない Dependency InjectionDead Simple Dependency Injectionを見てみます。

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 { /* ... */ }

そして、使用する D の実装を示すモジュールがある場合、インジェクターから A のインスタンスを要求するだけです。

A a = injector.createInstance(A.class);

上記の URL に示されている内容を考えると、上記のコードに相当する Scala はどのように見えるでしょうか?

FWIW、私はhttps://github.com/dickwall/subcut/blob/master/GettingStarted.mdも調査しており、単にアンチ DI ソリューションを理解しようとしています。

4

4 に答える 4

8

あなたが説明しているユースケースには、暗黙的なパラメーターで十分です。

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()

これで、次のように求めることができますA

val a = A()
于 2012-09-10T04:22:53.007 に答える
4

self-typesで解決できます。

A は B と C の両方に依存し、B と C の両方は D に依存します

したがって、次のように書くことができます。

class A {
  self: B with C => 
}

trait B { 
  self: D => 
}

trait C {
  self: D => 
}

trait D {}

次に、呼び出し側で:

val x = new A with BImpl with CImpl with DImpl

ただし、B、C、D クラスへの依存関係が解決されていないため、以下のコードはコンパイルされません。

val x = new A
于 2012-09-09T18:58:49.483 に答える
1

そのような依存性注入を提供するのは難しいです。上記の例のほとんどでは、クラスがインスタンス化される場所の近くに暗黙を作成する必要があります。

私が思いつくことができる最も近いものは次のとおりです。

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 */}
  }
}

そして、コードでは次のように使用します。

import Implicits._

object MyApplication {
   def main(args: Array[String]):Unit = {
      val a = new A
   }
}

(たとえば)テスト中に異なるバージョンを指定できるようにする必要がある場合は、次のようにすることができます。

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
}

これにより、 Implicits._ を任意のファイルにインポートするだけで済み、元の質問と同様のワークフローが提供されます。

ただし、ほとんどの場合、私はこの戦術を使用しません。インスタンスを作成するクラスで暗黙的に使用できるようにするだけです。

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
}

HereEは別のファイルで定義され、 のインスタンスを作成しますC。(経由で)に依存するそのドキュメントDに渡される必要があります。EEDC

于 2012-12-13T22:30:43.873 に答える
0

@ om-nom-nom の答えは、あなたが望むものに非常に近いと思います。これが私が持っているものです:

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)
于 2012-09-11T02:05:56.280 に答える