Шаблон построителя и объект конфигурации - PullRequest
29 голосов
/ 03 августа 2010

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

Использование компоновщика будет выглядеть так:

Product p = Product.Builder.name("Vodka").alcohol(0.38).size(0.7).price(17.99).build();

Очевидно, что это очень читабельно и кратко, но у вас естьДля реализации компоновщика:

public class Product {

    public final String name;
    public final float alcohol;
    public final float size;
    public final float price;

    private Product(Builder builder) {
        this.name = builder.name;
        this.alcohol = builder.alcohol;
        this.size = builder.size;
        this.price = builder.price;
    }

    public static class Builder {

        private String name;
        private float alcohol;
        private float size;
        private float price;

        // mandatory
        public static Builder name(String name) {
            Builder b = new Builder();
            b.name = name;
            return b;
        }

        public Builder alcohol(float alcohol) {
            this.alcohol = alcohol;
            return.this;
        }

        public Builder size(float size) {
            this.size = size;
            return.this;
        }

        public Builder price(float price) {
            this.price = price;
            return.this;
        }

        public Product build() {
            return new Product(this);
        }

    }

}

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

class ProductConfig {

        public String name;
        public float alcohol;
        public float size;
        public float price;

        // name is still mandatory
        public ProductConfig(String name) {
            this.name = name;
        }

}

public class Product {

    public final String name;
    public final float alcohol;
    public final float size;
    public final float price;

    public Product(ProductConfig config) {
        this.name = config.name;
        this.alcohol = config.alcohol;
        this.size = config.size;
        this.price = config.price;
    }

}

Использование:

ProductConfig config = new ProductConfig("Vodka");
config.alcohol = 0.38;
config.size = 0.7;
config.price = 17.99;
Product p = new Product(config);

Для этого использования требуется еще несколько строк, но он также очень удобочитаем, но реализация намного проще, и, возможно, его легче понять тем, кто не знаком с шаблоном компоновщика.Кстати: есть ли название для этого шаблона?

Есть ли недостаток в подходе конфигурации, который я пропустил?

Ответы [ 9 ]

16 голосов
/ 03 августа 2010

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

Эта развязка означает, что ваш код более удобен в обслуживании и его проще тестировать.

6 голосов
/ 03 августа 2010

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

Однако мне больше всего не хватает того, что шаблон компоновщика можно использовать для предоставления так называемых «плавных интерфейсов» .

Вместо этого:

ProductConfig config = new ProductConfig("Vodka");
config.alcohol = 0.38;
config.size = 0.7;
config.price = 17.99;
Product p = new Product(config);

Вы можете сделать:

ProductFactory.create()
    .drink("Vodka")
    .whereAlcohoolLevelIs(0.38)
    .inABottleSized(0.7)
    .pricedAt(17.99)
    .build();

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

В некоторых замечательных коллекциях Java, таких как коллекции Google, очень либерально и очень хорошо используются «плавные интерфейсы» . Я бы выбрал их в любой день вместо вашего «более простого для ввода / меньше символов» подхода:)

4 голосов
/ 03 августа 2010

Какую проблему вы пытаетесь решить с помощью вашего шаблона?Шаблон компоновщика используется для объектов со многими (необязательными) параметрами, чтобы предотвратить множество различных конструкторов или очень длинные.Он также поддерживает ваш объект в согласованном состоянии (по сравнению с шаблоном javabean) во время строительства.

Разница между компоновщиком и «объектом конфигурации» (похоже на хорошее имя) заключается в том, что вам все равно придется создавать объект с теми же параметрами с помощью конструктора или метода получения / установки.Это а) не решает проблему конструктора или б) держит объект конфигурации в несогласованном состоянии.Несогласованные состояния объекта конфигурации на самом деле не повреждают его, но вы можете передать незаконченный объект конфигурации в качестве параметра. [Ссылка Michids на фантомные типы, кажется, решает эту проблему, но это опять-таки убивает читабельность (new Foo<TRUE,TRUE, TRUE, FALSE, TRUE> своего рода отстой).] В этом большое преимущество шаблона компоновщика: вы можете проверить свои параметры перед созданиемобъект и вы можете вернуть любой подтип (действует как фабрика).

Объекты конфигурации действительны для наборов параметров, которые являются обязательными.Я видел этот шаблон много раз в .NET или Java раньше.

2 голосов
/ 03 августа 2010

Рассматривали ли вы использование builder-builder ?

Я думаю, что строитель (с такими префиксами, как «С») читает более естественно / свободно.

1 голос
/ 17 августа 2017

Шаблон конфигурации и шаблон компоновщика функционально эквивалентны. Они оба решают одни и те же проблемы -

  • Устранить необходимость использования нескольких подписей конструктора

  • Разрешить установку полей только во время строительства

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

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

1 голос
/ 18 сентября 2012

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

Что мне также нравится в методах получения / установки, так это то, что вы четко видите, что делаете: получаете или устанавливаете. Я чувствую, что со строителем я теряю немного интуитивной ясности здесь.

Я знаю, что многие люди читали определенную книгу, и теперь внезапно модель строителя наслаждается ажиотажем, как будто это был новый iPhone. Тем не менее, я не ранний усыновитель. Я использую «новый способ» только тогда, когда он действительно экономит время на любой территории, будь то производительность, обслуживание, кодирование ...

Мой практический опыт заключается в том, что мне обычно лучше работать с геттерами / сеттерами и конструкторами. Это позволяет мне повторно использовать эти POJO для любых целей.

Несмотря на то, что я вижу назначение вашего объекта конфигурации, я также думаю, что это еще больше, чем сборщик, и для чего? Что не так с сеттерами?

Может быть, нам нужно изобрести предложение WITH: Например, скажем, у вас есть

public Class FooBar() {
    private String foo;

    public void setFoo(String bar) { 
      this.foo = bar; 
    }

    public String getFoo() { 
        return this.foo; 
    }
}

public static void main(String []args) {

 FooBar fuBar = new FooBar();
 String myBar;

 with fuBar {
    setFoo("bar");
    myBar = getFoo(); 
 }
}

Ах, я не знаю ... Я думаю, что это может привести к более быстрой записи кода без всяких проблем с внутренним классом. Есть ли у кого-нибудь связь с гуру Oracle Java?

Это выглядит не так чисто, как использование объекта со строителем, но вы экономите время строителя. И вы все еще можете использовать этот класс как обычный pojo / bean, который можно использовать в фреймворках ...

Вам, ребята, действительно нравится этот пункт, или вы думаете, что он скорее отстой? Приветствия

1 голос
/ 03 августа 2010

IMO, шаблон компоновщика гораздо более надежен, если у вас есть такие вещи, как проверка и т. Д.

Шаблон компоновщика в вашем случае можно изменить, сделав следующее:

Product p = new ProductBuilder("pName").alcohol(0.38).size(0.7).price(17.99).build();

Метод build() может выполнять все проверки, необходимые для вашего сборщика.У шаблона компоновщика также есть несколько конструктивных особенностей (которые могут быть неприменимы в вашем случае).Для подробностей проверьте этот вопрос

0 голосов
/ 03 августа 2010

Основным недостатком является то, что этого нет в книге Джошуа, поэтому дроны не могут обернуть вокруг нее головы.

Вы используете простой объект-значение для хранения нескольких аргументов, в которых нуждается функция (/ method / constructor), в этом нет ничего плохого, это было сделано целую вечность. Пока у нас нет названных необязательных параметров, нам придется придумывать обходные пути, подобные этому - это позор, а не какие-то чертовски блестящие изобретения богов на Солнце.

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

Кто мы, чтобы подражать этому?

0 голосов
/ 03 августа 2010

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...