Мотивация
Недавно я искал способ инициализации сложного объекта, не передавая конструктору много параметров. Я попробовал это с шаблоном построителя, но мне не нравится тот факт, что я не могу проверить во время компиляции, если я действительно установил все необходимые значения.
Традиционный шаблон построителя
Когда я использую шаблон построителя для создания моего объекта Complex
, создание более "типично", потому что легче увидеть, для чего используется аргумент:
new ComplexBuilder()
.setFirst( "first" )
.setSecond( "second" )
.setThird( "third" )
...
.build();
Но теперь у меня есть проблема, что я могу легко пропустить важный параметр. Я могу проверить его внутри метода build()
, но это только во время выполнения. Во время компиляции ничего не предупреждает меня, если я что-то пропустил.
Улучшенный шаблон построителя
Теперь моя идея состояла в том, чтобы создать строителя, который "напоминает" мне, если я пропустил необходимый параметр. Моя первая попытка выглядит следующим образом:
public class Complex {
private String m_first;
private String m_second;
private String m_third;
private Complex() {}
public static class ComplexBuilder {
private Complex m_complex;
public ComplexBuilder() {
m_complex = new Complex();
}
public Builder2 setFirst( String first ) {
m_complex.m_first = first;
return new Builder2();
}
public class Builder2 {
private Builder2() {}
Builder3 setSecond( String second ) {
m_complex.m_second = second;
return new Builder3();
}
}
public class Builder3 {
private Builder3() {}
Builder4 setThird( String third ) {
m_complex.m_third = third;
return new Builder4();
}
}
public class Builder4 {
private Builder4() {}
Complex build() {
return m_complex;
}
}
}
}
Как вы можете видеть, каждый установщик класса строителя возвращает другой класс внутреннего строителя. Каждый внутренний класс строителя предоставляет ровно один метод setter, а последний - только метод build().
Теперь конструкция объекта будет выглядеть следующим образом:
new ComplexBuilder()
.setFirst( "first" )
.setSecond( "second" )
.setThird( "third" )
.build();
... но нет способа забыть необходимый параметр. Компилятор не согласился с этим.
Необязательные параметры
Если бы у меня были необязательные параметры, я бы использовал последний класс встроенного builder Builder4
, чтобы установить их как "традиционный" построитель, возвращаясь.
Вопросы
- Это хорошо известный шаблон? У него есть специальное имя?
- Вы видите какие-то подводные камни?
- Есть ли у вас идеи улучшить реализацию - в смысле меньшего количества строк кода?