Может ли шаблон строителя делать слишком много? - PullRequest
3 голосов
/ 19 января 2011

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

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

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

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

Ответы [ 5 ]

5 голосов
/ 25 ноября 2012

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

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

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

  1. Запись шагов создания во внутренних классах или интерфейсах, где каждый метод знает, что может быть отображено далее.
  2. Реализуйте все ваши интерфейсы шагов во внутреннем статическом классе.
  3. Последний шаг - BuildStep, отвечающий за создание объекта, который вам нужно построить.
5 голосов
/ 19 января 2011

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

  • Создание объектов, имеющих несколько допустимых конфигураций
    • Я думаю, что ваш автомобиль - отличный пример
  • Создание неизменных объектов, где не все необходимые данные могут быть предоставлены заранее
    • Отличным примером этого является пример создателей неизменяемой коллекции гуавы, например 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();
2 голосов
/ 19 января 2011

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

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

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

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

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

2 голосов
/ 19 января 2011

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

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

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

0 голосов
/ 19 января 2011

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

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

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

...