Имея шаблон ниже строителя в Scala. Чтобы упростить это, я использую 3 экземпляра A
, так что instance1
содержит только field1
и не имеет подключения к field2
или field3
. Проблема в том, что везде в коде я должен использовать val s = A.instance1.field1.get; doSomething(s)
, где вызов get
не является потенциально безопасным. Например, A.instance1.field2.get
потерпит неудачу на None.get
. Для того, чтобы охранять его, я должен соответствовать делу против варианта и иметь дело ни с кем случаями:Scala Builder шаблон с фантомными типами
object A {
val instance1 = new ABuilder().withField1("abc").build1
val instance2 = new ABuilder().withField1("abc").withField2("def").build2
val instance3 = new ABuilder().withField1("abc").withField3("def").build1
}
case class A(builder: ABuilder) {
val field1: Option[String] = builder.field1
val field2: Option[String] = builder.field2
val field3: Option[String] = builder.field3
}
class ABuilder {
var field1: Option[String] = None
var field2: Option[String] = None
var field3: Option[String] = None
def withField1(f: String): ABuilder = {
this.field1 = Some(f)
this
}
def withField2(f: String): ABuilder = {
this.field2 = Some(f)
this
}
def withField3(f: String): ABuilder = {
this.field3 = Some(f)
this
}
def build1: A = {
require(field1.isDefined, "field 1 must not be None")
A(this)
}
def build2: A = {
require(field1.isDefined, "field 1 must not be None")
require(field2.isDefined, "field 2 must not be None")
A(this)
}
}
Другим решением было бы использовать параметризованные типы, называемые также фантомные тип. Я нашел очень мало хороших учебников по этому вопросу и не смог найти ни в одном из них, как реализовать шаблон безопасного шаблона типа в Scala с фантомными типами и фактическими данными (или состоянием) - все примеры описывают только методы.
Как я могу использовать типы фантомов в моем примере, чтобы избежать исключений во время выполнения None
и получить только прекрасные исключения типа-несоответствия? Я пытаюсь параметризовать все упомянутые классы и методы и использовать закрытые черты, но пока не добился успеха.
Может FIELD2 или field3 имеют значения по умолчанию? –
Нет, я пытаюсь не использовать '.getOrElse', но использовать два разных подтипа строителей. Этот пример относится к типам фантомов или параметризованным типам и их границам. –
Для этого вам не нужны фантомные типы. Просто заставьте ваш строитель принять требуемый параметр в конструкторе: 'new ABuilder (" foo ") .FFF2 (" bar ")' – Dima