Как объявить анонимный микс, используя параметр типа в Scala

#scala

#scala

Вопрос:

Было задано несколько вопросов, которые в некоторой степени связаны с этой проблемой, но, похоже, они не совсем подходят.

Я использую шаблон Cake, чтобы внедрить систему «Хранения» в производственный код, а систему хранения заглушек — в целях тестирования. Это все замечательно, но есть класс, который создается внутри исходного класса, к которому также должна быть подключена эта система хранения заглушек. Поскольку он скрыт внутри реализации, у меня нет к нему доступа.

Все выглядит следующим образом:

 class Main { this: Storage =>
  ...
  val used = Used(...)
  ...
}

class Used { this: Storage =>
  ...
}
  

При тестировании «Used» я просто new Used with StubStorage и ухожу. Раньше я делал то же самое с Main , но это было до того, как он начал использовать Used . Теперь, когда Main создается наивный экземпляр Used , у меня возникла эта проблема.

Я хотел попробовать это таким образом:

 class Main[T <: Storage] { this: T =>
  ...
  val used = Used[T](...)
  ...
}

class Used[T <: Storage] { this: T =>
  ...
}
object Used {
  def apply[T <: Storage](...) = new Used(...) with T
}
  

Но, конечно, это не работает, потому что компилятору недостаточно информации для обнаружения T . Есть ли волшебный рецепт для этого? Я немного поиграл с ним, и он кажется достаточно громоздким, чтобы стандартный метод внедрения OO доставлял меньше проблем, но я мог что-то упустить.

Я рассмотрел концепцию неявной фабрики, но я не могу придать ей форму, чтобы работать с mixins.

РЕДАКТИРОВАТЬ: Удивительно, какую ясность дает публичное написание вопроса. 🙂 Я не решил проблему так, как я изначально предполагал, но есть простое решение реальной проблемы:

 trait UsedProvider {
  def createUsed = Used.apply _
}

class Main { this: Storage with UsedProvider =>
  val used = createUsed(...)
}
  

Тогда я бы просто сделал следующее в тесте: new Main with StubStorage with StubUsedProvider .

Ответ №1:

Я тоже не решил вашу первоначальную проблему, но рассматривали ли вы возможность использования абстрактного класса для Main и предоставления значения для used там, где оно вам нужно?

 abstract class Main { this: Storage =>
  val s = "s"
  val used: Used
}
  

Затем создайте экземпляр следующим образом:

 val main = new Main with StubStorage { val used = new Used(s) with StubStorage }
  

Комментарии:

1. Это позволило бы мне создать только один, а мне нужно больше одного, что не было ясно в исходном вопросе. Что мне нужно, так это фабричный метод, который позволяет мне создавать их, когда они мне нужны. Так что я просто снова использую шаблон good ol ‘ cake, чтобы получить эту зависимость.