Skip to main content
 首页 » 编程设计

scala之使用 Reader Monad 进行依赖注入(inject)

2024年12月31日698°冷暖

最近看了讲座Dead-Simple Dependency InjectionDependency Injection Without the Gymnastics关于与 Monads 的 DI 并印象深刻。我试图将它应用于一个简单的问题,但一旦它变得不平凡就失败了。我真的很想看到一个运行版本的依赖注入(inject)

  • 一个类,它依赖于多个必须注入(inject)的值
  • 一个依赖于某个类的类,该类依赖于要注入(inject)的东西

  • 如下例所示
    trait FlyBehaviour { def fly() } 
    trait QuackBehaviour { def quack() } 
    trait Animal { def makeSound() } 
     
    // needs two behaviours injected 
    class Duck(val flyBehaviour: FlyBehaviour, val quackBehaviour: QuackBehaviour) extends Animal  
    { 
       def quack() = quackBehaviour.quack() 
       def fly() = flyBehaviour.fly() 
       def makeSound() = quack() 
    } 
     
    // needs an Animal injected (e.g. a Duck) 
    class Zoo(val animal: Animal) 
     
    // Spring for example would be able to provide a Zoo instance 
    // assuming a Zoo in configured to get a Duck injected and 
    // a Duck is configured to get impl. of FlyBehaviour and QuackBehaviour injected 
    val zoo: Zoo = InjectionFramework.get("Zoo") 
    zoo.animal.makeSound() 
    

    使用阅读器 Monad 查看示例实现将非常有帮助,因为我只是觉得我错过了朝着正确方向的插入。

    谢谢!

    请您参考如下方法:

    “读者单子(monad)”只是 Function1 ,所以你需要做的就是接受一个包含你需要的所有东西的参数。例如:

    trait Config { 
       def fly: FlyBehaviour 
       def quack: QuackBehaviour 
    } 
     
    type Env[A] = Config => A 
    

    现在如果你想构造一个 Duck基于这个环境:
    val a: Env[Animal] = c => new Duck(c.fly, c.quack) 
    

    然后构造一个 Zoo基于此很容易:
    val z: Env[Zoo] = a andThen (new Zoo(_)) 
    

    使用 Scalaz (或者你自己做一些工作)你可以利用一些语法细节来“询问”配置 c :
    val z: Env[Zoo] = for { 
      c <- ask 
    } yield new Zoo(Duck(c.fly, c.quack))