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