How to avoid dependency injection in Scala?

前端 未结 4 1892
爱一瞬间的悲伤
爱一瞬间的悲伤 2021-02-10 06:34

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

4条回答
  •  终归单人心
    2021-02-10 07:09

    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.

    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.

    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. We require D to be passed to E and with that document that E depends on D (via C).

提交回复
热议问题