Предположим, у нас есть черта T
. Каков наилучший способ добиться следующего:
- Каждый, кто пишет реализацию
T
, должен быть вынужден предоставить возможность, позволяющую инициализироватьT
без параметров, т. е. нам, вероятно, придется принудительно реализовать реализацию настраиваемой фабрики. - Вся логика/данные, которые зависят только от фактических параметров инициализации (определенной реализации
A
илиT
), должны обрабатываться/храниться централизованно, но должны быть доступны как на фабрике, так и наA
.
Самый простой/краткий способ, который я вижу для достижения этого (приблизительно), состоит в том, чтобы добавить трейт для фабрики и связать T
с этой фабрикой:
trait T {
val factory: TFactory
}
trait TFactory {
def build(): T
val description: String // example for logic/data that only depend on the parameters
}
// example implementation:
class A(val factory: AFactory, paramA: Int, paramB: Int, paramC: Int) extends T
class AFactory(paramA: Int, paramB: Int, paramC: Int) extends TFactory {
def build = new A(this, paramA, paramB, paramC)
val description = f"$paramA $paramB $paramC"
}
Очевидно, что на самом деле это не «принуждает» реализацию фабрики (пока доступна альтернативная реализация), и, очевидно, можно генерировать экземпляры A
, которые ссылаются на «неправильный» TFactory
. Что мне также не нравится в этом подходе, так это повторение параметров инициализации. Я часто создаю еще один класс AParams
, который снова оборачивает все параметры (например, чтобы облегчить добавление новых параметров). Таким образом, я получаю три класса, которые, по моему мнению, являются шаблонными для этой простой задачи.
Мой вопрос в том, существует ли (возможно, совершенно) другой подход, который достигает тех же основных целей, но является более кратким?