Может ли шаблон Builder делать слишком много?

Недавно я изучал шаблоны проектирования с исследовательской группой и пришел к выводу, что шаблон построителя может быть очень полезен для создания сложных объектов, состоящих из многих (потенциально необязательных) частей.

Однако бывает ли когда-нибудь, что строитель делает слишком много? Допустим, у нас есть класс, который имеет много разных комбинаций объектов, есть ли другой шаблон, который лучше подходит для этого, вместо того, чтобы создавать десятки разных конструкторов? Можно ли уменьшить количество необходимых вам билдеров, не создавая полностью специфические билдеры?

Примером, к которому я и моя исследовательская группа постоянно возвращались, был автостроитель, например, на веб-сайте автомобильной компании. У любой автомобильной компании есть десятки автомобилей, каждый из которых имеет множество различных функций, цветов, дополнений и т. д. Насколько я понимаю, ваш конструктор должен быть специфичным для конкретного объекта, который вы создаете, поэтому применение шаблона конструктора к этому примеру даст сотни строители, которые выглядят как «RedSUVWithSunroofBuilder», «BlueSUVWithSunroofBuilder», «RedSUVBuilder» и т. д.

Есть ли какая-то причина, по которой, используя шаблон построителя, я не мог передать некоторые из этих значений, чтобы уменьшить количество построителей, которые мне нужно было бы создать? Например, вместо использования RedSUVWithSunroofBuilder или BlueSUVWithSunroofBuilder по-прежнему подходит шаблон строителя для выполнения SUVWithSunroofBuilder("Red") и SUVWithSunroofBuilder("Blue"), или это больше подходит для другого шаблона?


person Nick DeFazio    schedule 19.01.2011    source источник
comment
Я бы сказал, что строитель может делать слишком мало. Как вы говорите, конструктор хорош для создания сложных объектов. Строитель делает слишком много, создавая слишком много возможных объектов. например у вас может быть один глобальный построитель для каждого объекта в вашей системе. Это, вероятно, будет слишком много.   -  person Peter Lawrey    schedule 19.01.2011
comment
На самом деле это не ответ, но, естественно, каждый шаблон проектирования можно использовать слишком часто. И не все аккуратно вписывается в шаблоны. Если у вас есть большое количество различных объектов для создания, вы, вероятно, захотите сохранить детали в базе данных и построить их оттуда.   -  person biziclop    schedule 19.01.2011


Ответы (5)


Шаблон построителя, безусловно, является дискреционным, если он слишком сложен, то он слишком сложен, и вы можете рассмотреть другой способ создания объектов, например заводской шаблон. Я думаю, что есть несколько сценариев, в которых шаблон строителя превосходен:

  • Creating objects that have several valid configurations
    • I think your car thing is a great example
  • Creating immutable objects where not all required data can be supplied up front
    • For a great example of this check out the guava immutable collection builders for instance ImmutableSet.Builder

Вот один из примеров того, как можно реализовать конструктор автомобилей:

public class Car {
    private final boolean hasSunroof;
    private final Color color;
    private final int horsePower;
    private final String modelName;

    private Car(Color color, int horsePower, String modelName, boolean hasSunroof) {
        this.color = color;
        this.horsePower = horsePower;
        this.hasSunroof = hasSunroof;
        this.modelName = modelName;
    }

    public static Builder builder(Color color, int horsePower) {
        return new Builder(color, horsePower);
    }

    public static class Builder {
        private final Color color;
        private final int horsePower;
        private boolean hasSunroof;
        private String modelName = "unknown";

        public Builder(Color color, int horsePower) {
            this.color = color;
            this.horsePower = horsePower;
        }

        public Builder withSunroof() {
            hasSunroof = true;
            return this;
        }

        public Builder modelName(String modelName) {
            this.modelName = modelName;
            return this;
        }

        public Car createCar() {
            return new Car(color, horsePower, modelName, hasSunroof);
        }
    }
}

Builder не обязательно должен быть вложенным классом, но он позволяет скрыть ваши конструкторы от людей, которые могут злоупотреблять вашим API. Также обратите внимание, что минимальные необходимые параметры должны быть предоставлены даже для создания построителя. Вы можете использовать этот конструктор следующим образом:

Car car = Car.builder(Color.WHITE, 500).withSunroof().modelName("Mustang").createCar();
person jtb    schedule 19.01.2011

Что ж, несколько месяцев назад я задался тем же вопросом и придумал новый шаблон проектирования под названием step builder pattern (полное описание этого шаблона здесь).

В этом дизайне я даю возможность проектировать пути, избегая необходимости создавать несколько строителей.

Концепция проста:

  1. Напишите этапы создания во внутренних классах или интерфейсах, где каждый метод знает, что может отображаться дальше.
  2. Реализуйте все свои интерфейсы шагов во внутреннем статическом классе.
  3. Последним шагом является BuildStep, отвечающий за создание объекта, который вам нужно построить.
person marcocast    schedule 25.11.2012

Шаблон Builder, который вы обычно видите (особенно в Java), представляет собой один Builder для данного объекта, который имеет гибкий интерфейс для установки различных параметров. Это шаблон, пропагандируемый в Effective Java, и именно поэтому вы обычно видите это в Java.

Если у вас есть несколько очень разных сценариев строительства, разные объекты строителя, конечно, могут иметь смысл, но я бы сделал шаг назад. Если у вас так много разных свойств в одном объекте, у вас может быть объект, делающий слишком много, и симптомом проблемы является сложность компоновщиков.

Конечно, объекты реального мира сложны, но основной тезис объектно-ориентированного проектирования заключается в том, что если сложность распределяется по уровням абстракций, так что на каждом заданном уровне вы имеете дело с 5–7 свойствами одновременно, вы можете ограничить проблему от того, чтобы она превратилась в проблему. слишком сложно понять на данном уровне.

Сложность правильного проектирования слоев абстракции делает вышеизложенное таким же идеализмом, как и реальностью, но я думаю, что смысл в том, чтобы Объект делал слишком много, остается в силе.

В примере с вашим автомобилем автомобиль состоит из многих слоев, но хитрость в том, чтобы сохранить это управляемым, будет состоять в том, чтобы различать различные сборки и создавать более крупный автомобиль из нескольких вариантов сборки, которые сами состоят из нескольких вариантов сборки и т. д. Каждая сборка заслуживает отдельного объекта и, возможно, собственного строителя.

person Yishai    schedule 19.01.2011

Мне кажется, что вы используете слишком много билдеров, и каждый билдер делает недостаточно. У вас должен быть один строитель для каждого класса. Кажется, вы пытаетесь создать новый построитель для каждого набора значений полей. Вместо этого каждое поле должно иметь один или два метода в одном конструкторе. Ваши вызовы строителя должны выглядеть примерно так

Car c = new SUVBuilder().withSunroof().withColor("Red").build();

Вышеизложенное предполагает, что внедорожник является подклассом автомобиля. Если это не так, то вы можете указать внедорожник в дополнительной функции.

person ILMTitan    schedule 19.01.2011

Строители позволяют инкапсулировать сложную серию вариантов в простой алгоритм. Например, если ваша сборочная линия собирает автомобиль, она может:

buildChassis();
buildDriveTrain();
buildBody();
assemble();
paint();

Возможно, вам понадобятся отдельные конструкторы бетона для разных шасси, трансмиссий и кузовов, но, вероятно, вам может сойти с рук только один для окраски — вы просто параметризуете его для цвета в c'tor. Ваш директорский класс знает, каковы детали вашего построителя, поэтому он создает правильные конкретные построители; ваш конвейерный клиент просто выполняет шаги по порядку. Вы можете параметризовать конкретных строителей для любых деталей, которые не являются фундаментальными (а что является фундаментальным, так это суждение).

person Jerry Andrews    schedule 19.01.2011
comment
И чтобы расширить точку зрения Ишая: более сложные бетонные строители выступают в качестве клиентов для более простых строителей, тем самым реализуя многоуровневую конструкцию, которую он описывает. - person Jerry Andrews; 19.01.2011