22

私は最近、MonadsとDIについて約Dead-Simple Dependency InjectionDependency Injection Without the Gymnasticsという話を見て感動しました。私は単純な問題でそれを適用しようとしましたが、それが簡単ではないとすぐに失敗しました。私は本当に依存性注入にReader Monadを使用する

  • 依存性注入の実行中のバージョンを注入することに何かに依存クラスに依存
  • クラスに注入する必要がある複数の値に依存してクラスを参照してくださいしたいと思います次の例のよう

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

私だけの料金であるため、読者モナドを使ってサンプル実装を見て、本当に役立つだろう私は正しい方向へのプッシュを欠いている。

ありがとうございます!

答えて

26

"読者モナド"はちょうどFunction1です。あなたが必要とするのは、必要なものすべてを含む議論を受け入れることだけです。たとえば、次のように今、あなたはこのような環境に基づいてDuckを構築したい場合は

trait Config { 
    def fly: FlyBehaviour 
    def quack: QuackBehaviour 
} 

type Env[A] = Config => A 

val a: Env[Animal] = c => new Duck(c.fly, c.quack) 

そして、それに基づいてZooを構築するのは簡単です:

Scalazを使用して
val z: Env[Zoo] = a andThen (new Zoo(_)) 

(または自分で少し作業をして)、設定を「尋ねる」ためにいくつかの構文の細かい点を利用することができますc

val z: Env[Zoo] = for { 
    c <- ask 
} yield new Zoo(Duck(c.fly, c.quack)) 
+0

ありがとうございます。私は好奇心が強いですか、あなたはDIを使って春やガレージの代わりにこれを使っていますか?あなたの経験によればそれは好ましいですか? –

+2

はい、私たちはこれを広範囲に使用しており、非常に望ましいです。私が春やGuiceをもう一度見たら、それは早すぎるでしょう。 – Apocalisp

+0

@Apocalisp、このソリューションをhttp://stackoverflow.com/questions/12341867/how-to-avoid-dependency-injection-in-scala/12363015#12363015に適用することはできますか? –