Подтвердить что ты не робот

Использование Reader Monad для инъекций зависимостей

Недавно я видел переговоры "Зависимость от мертвой простой зависимости" и "Инъекция зависимостей без гимнастики" относительно DI с Монады и были впечатлены. Я попытался применить его к простой проблеме, но потерпел неудачу, как только получился нетривиальный. Я действительно хотел бы увидеть запущенную версию инъекции зависимостей, где

  • класс, который зависит от более чем одного значения, которое должно быть введено
  • класс, который зависит от класса, который зависит от того, что нужно вставить

как в следующем примере

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, так как я просто чувствую, что мне не хватает толчка в правильном направлении.

Спасибо!

4b9b3361

Ответ 1

"Мода читателя" всего лишь 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))