Классы типов Scala с внедрением зависимости конструктора - PullRequest
0 голосов
/ 18 октября 2018

Я пытаюсь выяснить, как заставить традиционную инъекцию зависимостей на основе конструктора работать с шаблонами классов типов.

Например, учитывая

trait MyTypeClass[A] {
  def doSomething(a: A): Unit
}

class TypeClasses(prefix: String) {

  implicit val stringTC = new MyTypeClass[String] {
    def doSomething(a: String) = println(s"$prefix a")
  }

  implicit val intTc = new MyTypeClass[Int] {
    def doSomething(a: Int) = println(s"s$prefix $a")
  }
}

class MyLogic {

  def doSomething[A](a: A)(implicit myTypeClass: MyTypeClass[A]) = myTypeClass.doSomething(a)

  doSomething("Hello world")
}

Что было бы лучшеспособ получить экземпляры класса неявного типа внутри экземпляра TypeClasses в MyLogic?

Единственное, что я придумал, это либо
a) Внедрить экземпляр TypeClassesв MyLogic в конструкторе, а затем import instanceOfTypeClasses._.Однако у этого есть недостаток, заключающийся в том, что он должен повторяться для каждого класса, и подклассы не могут наследовать импорт.
или b) делают TypeClasses признаком, prefix определением и имеют MyLogic расширяют TypeClasses и затем зависимость вводит экземпляр для prefix в конструкторе.Однако это становится грязным, поскольку позволяет TypeClasses перетекать в MyLogic.

.

1 Ответ

0 голосов
/ 24 октября 2018

Если вам нужно внедрение зависимостей , как я могу предположить из ваших тегов, вы можете попробовать использовать distage ( слайды ) DI-фреймворк для Scala (Отказ от ответственности: я автор).

Он поддерживает внедрение экземпляра класса типов.

Поскольку ваши экземпляры класса типов создаются динамически в классе TypeClasses, вы должны добавить параметр конструктора TypeClasses вкаждый класс, который должен вызвать функцию, которая требует экземпляра класса типов.Но вы можете удалить шаблон import typeclasses._, создав неявные определения, которые будут извлекать экземпляры из объекта TypeClasses, если он доступен как неявный:

trait MyTypeClass[A] {
  def doSomething(a: A): Unit
}

object MyTypeClass {
  implicit def intFromTypeClasses(implicit typeClasses: TypeClasses): MyTypeClass[Int] = typeClasses.intTc
  implicit def stringFromTypeClasses(implicit typeClasses: TypeClasses): MyTypeClass[String] = typeClasses.stringTC
}

Поскольку неявные определения определены в сопутствующем объекте дляMyTypeClass они всегда будут доступны без какого-либо импорта.

Затем вы должны добавить TypeClasses в качестве неявного параметра в MyLogic, это сделает его доступным для неявных определений для извлечения экземпляров из:

class MyLogic(implicit typeClasses: TypeClasses) {

  def doSomething[A](a: A)(implicit myTypeClass: MyTypeClass[A]) = myTypeClass.doSomething(a)

  doSomething("Hello world")
  // same as doSomething("Hello world")(MyTypeClass.stringFromTypeClasses(typeClasses))
}

Затем в distage объявите следующие привязки

import distage._

class MyAppModule extends ModuleDef {
  make[String].from("myprefix")
  make[TypeClasses]
  make[MyLogic]
}

И все подключено:

val ctx: Locator = Injector().produce(new MyAppModule)

implicit val typeClasses = ctx.get[TypeClasses]
ctx.get[MyLogic].doSomething("Hello world")
...