Java лучший способ реализовать шаблон построителя
Какое из следующего является лучшим подходом к реализации шаблона построителя?
1) Используя объект для сборки вместо всех его свойств в построителе (и создайте его в конструкторе конструктора):
public class Person {
private String firstName;
// other properties ...
private Person() {}
// getters ...
public static class Builder {
// person object instead of all the person properties
private Person person;
public Builder() {
person = new Person();
}
public Builder setFirstName(String firstName) {
person.firstName = firstName;
return this;
}
// other setters ...
public Person build() {
if (null == person.firstName) {
throw new IllegalStateException("Invalid data.");
}
return person;
}
}
}
2) Используя свойства объекта для сборки вместо объекта непосредственно в построителе (и создайте его в методе build()):
public class Person {
private String firstName;
// other properties ...
private Person() {}
// getters ...
public static class Builder {
// person properties instead of object
private String firstName;
// other properties ...
public Builder() {}
public Builder setFirstName(String firstName) {
this.firstName = firstName;
return this;
}
// other setters ...
public Person build() {
if (null == this.firstName) {
throw new IllegalStateException("Invalid data.");
}
Person person = new Person();
person.firstName = firstName;
return person;
}
}
}
Я предпочитаю первый способ, потому что считаю, что с множеством свойств повторить их в построителе избыточно. Существуют ли некоторые недостатки с первым подходом?
Спасибо заранее и извините за мой плохой английский.
Ответы
Ответ 1
Маленькое примечание. Да, свойства могут быть повторением, но у них есть преимущества.
Подробности ниже:
Если вы посмотрите на детали здесь.
Pizza pizza = new Pizza(12);
pizza.setCheese(true);
pizza.setPepperoni(true);
pizza.setBacon(true);
Проблема заключается в том, что, поскольку объект создается по нескольким вызовам, он может находиться в несогласованном состоянии частично через его конструкцию. Это также требует больших усилий для обеспечения безопасности потоков.
Лучшей альтернативой является использование шаблона Builder.
Обратите внимание, что метод в Builder и соответствующий конструктор или родительский класс Pizza - полный код в ссылке здесь
public static class Builder {
public Pizza build() { // Notice this method
return new Pizza(this);
}
}
private Pizza(Builder builder) { // Notice this Constructor
size = builder.size;
cheese = builder.cheese;
pepperoni = builder.pepperoni;
bacon = builder.bacon;
}
Ответ 2
Шаблон Builder
описан в книге "Банки четырех" "Образцы рисунков", в которой говорится:
Шаблон-конструктор - это шаблон проектирования, который позволяет поэтапно создавать сложные объекты с использованием правильной последовательности действий. Конструкция контролируется объектом-директором, который должен знать только тип объекта, который он должен создать.
Если существует последовательность шагов, которые должны выполняться при построении объекта, тогда перейдите к второй опции.
В вашем первом правиле правильная последовательность действий не контролируется. Вы можете перейти для любой опции, если последовательность действий не определена.
Ответ 3
Я думаю, что в вашем случае нет места, где можно создать объект. Строитель будет использоваться одинаково в обоих случаях с минимальной разницей в производительности.
Но если объект неизменен, и поле может быть создано более чем на один шаг, я бы, конечно, пошел со вторым подходом. Например, вы можете проверить исходный код java.lang.StringBuilder
и увидеть, что объект String
создан на последнем шаге:
public String toString() {
// Create a copy, don't share the array
return new String(value, 0, count);
}
Кроме того, я предпочитаю шаблон мастера. Это расширение шаблона Builder, которое защищает вас от получения исключения IllegalStateException.
public class Person {
private String firstName;
// other properties ...
private Person() {}
// getters ...
public static class Builder {
public Builder() {}
public FirstStep setFirstName(String firstName) {
return new FirstStep(firstName);
}
public static class FirstStep {
private String firstName;
private FirstStep(String firstName) {
this.firstName = firstName;
}
public Person build() {
Person person = new Person();
person.firstName = firstName;
return person;
}
}
}
}