24

私は最近、Monads を使用した DI に関するDead-Simple Dependency InjectionDependency Injection Without the Gymnasticsの講演を見て感銘を受けました。単純な問題に適用しようとしましたが、自明でなくなるとすぐに失敗しました。依存性注入の実行中のバージョンを実際に見たいと思っています

  • 注入する必要がある複数の値に依存するクラス
  • 注入される何かに依存するクラスに依存するクラス

次の例のように

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 を使用したサンプル実装を見ることは本当に役に立ちます。なぜなら、私は正しい方向へのプッシュを逃していると感じているからです。

ありがとう!

4

1 に答える 1

27

「reader モナド」は単なる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を使用する(または自分で少し作業することで)、 config を「尋ねる」ためにいくつかの構文の優れた点を利用できますc

val z: Env[Zoo] = for {
  c <- ask
} yield new Zoo(Duck(c.fly, c.quack))
于 2012-07-01T04:04:04.927 に答える