Мотивация
Недавно я искал способ инициализации сложного объекта без передачи большого количества параметров конструктору. Я попробовал это с шаблоном компоновщика, но мне не нравится тот факт, что я не могу проверить во время компиляции, действительно ли я установил все необходимые значения.
Традиционный образец строителя
Когда я использую шаблон построителя для создания моего 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;
}
}
}
}
Как видите, каждый установщик класса построителя возвращает свой внутренний класс построителя. Каждый внутренний класс построителя предоставляет ровно один метод установки, а последний предоставляет только метод build ().
Теперь конструкция объекта снова выглядит так:
new ComplexBuilder()
.setFirst( "first" )
.setSecond( "second" )
.setThird( "third" )
.build();
... но нет способа забыть необходимый параметр. Компилятор не примет это.
Необязательные параметры
Если бы у меня были необязательные параметры, я бы использовал последний внутренний класс компоновщика Builder4
, чтобы установить их как "традиционный" компоновщик, возвращающий себя.
Вопросы
- Это хорошо известный паттерн? У него есть специальное имя?
- Видите ли вы какие-либо подводные камни?
- У вас есть идеи по улучшению реализации - в смысле меньшего количества строк кода?