На прошлой неделе я писал о том, что делает шаблон анти-паттерном. На этой неделе я представляю шаблон дизайна … или подожду … возможно, это анти-шаблон. Или это? Давай посмотрим!
Шаблон построителя — это стиль программирования, когда существует класс, который создает экземпляр другого. Первоначальная цель шаблона построения состоит в том, чтобы отделить процесс построения объекта, который в некоторых случаях может быть довольно сложным, от класса самого объекта, таким образом, конструктор может доставлять различные типы объектов на основе хода процесса строительства. Это яркий пример разделения интересов.
Неизменяемые объекты — это объекты, которые создаются и не могут быть изменены после процесса создания.
Строители и неизменяемые объекты просто объединяются очень естественно.
Строитель и построенные объекты очень тесно связаны, и поэтому они обычно помещаются в одну упаковку. Но почему они реализованы в отдельных классах? С одной стороны: они должны быть отдельными классами, конечно. В этом все дело. Но с другой стороны: почему строитель не может быть внутренним классом встроенного класса? Строитель обычно собирает информацию о здании в своем собственном состоянии, и когда вызывающая сторона запрашивает объект, который будет построен, эта информация используется для создания построенного объекта. Это «использование» является операцией копирования большую часть времени. Если строитель является внутренним классом, вся эта информация может храниться во встроенном объекте. Обратите внимание, что внутренний класс может получить доступ ко всем закрытым частям класса, внедряющим его. Строитель может создать построенный объект, который еще не готов, и сохранить в нем информацию о сборке. По просьбе построить все, что он делает, это окончательные картины
Этот образец сопровождается гуавой для неизменных коллекций. Строители — это статические внутренние классы. Если вы посмотрите на код ImmutableList, вы увидите, что внутри абстрактного класса есть внутренний класс Builder
.
Но это не единственный способ встроить конструктор и реализацию. Что если мы встроим реализацию внутри компоновщика? Конструктор — это единственный код, который требует изменяемого доступа к классу. Интерфейса, определяющего методы запросов, которые реализует класс, должно быть достаточно для всех остальных. И если мы дошли до этой точки, почему бы не создать матрешку?
Давайте иметь интерфейс. Позволяет иметь конструктор внутри интерфейса как внутренний класс (статический и публичный по умолчанию и не может быть другим способом). Давайте иметь реализацию внутри компоновщика как частный статический класс, реализующий внешний интерфейс.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
public interface Knight { boolean saysNi(); public class Builder { private Implementation implementation = new Implementation(); public Builder setState(String say) { implementation.say = say; return this ; } public Implementation build() { Implementation knight = implementation; implementation = null ; return knight; } private static class Implementation implements Knight { private String say; public boolean saysNi() { return say.indexOf( "ni" ) != - 1 ; } } } } |
Строитель может получить доступ к любым полям реализации Knight, поскольку они находятся в одном классе верхнего уровня. (JLS1.7, раздел 6.6.1 Определение доступности)
Нет другого способа (кроме неприятных уловок отражения или злоупотребления байт-кодом, которые пока не входят в сферу) получить доступ к реализации, кроме использования компоновщика.
Конструктор может использоваться для построения реализации, и после того, как он вернул ее, он больше не имеет к ней доступа, и нет способа изменить реализацию через построитель. Если реализация является неизменяемой, это гарантирует сохранение состояния.
Это шаблон или антипаттерн?