Каков пересмотренный образец строителя? - PullRequest
16 голосов
/ 01 февраля 2011

В чем разница между исходным шаблоном Builder от GoF и «пересмотренным шаблоном GoF Builder» Джошуа Блоха?

Ответы [ 2 ]

11 голосов
/ 01 февраля 2012

Замечание по поводу Ответ Микко : Пример Хансена имеет несколько проблем - или, по крайней мере, отличия от версии Блоха, хотя я считаю, что версия Блоха лучше.

В частности:

Во-первых, поля Widget задаются в Builder.build(), а не в конструкторе Widget, и поэтому не являются (и не могут быть) final. Widget считается неизменным, но ничто не мешает другому программисту прийти и добавить сеттеры позже.

Во-вторых, комментарии в методе сборки Хансена говорят: «Проверка перед созданием начинается здесь». Блох (EJ 2ed. Стр.15) говорит:

Очень важно, чтобы [инварианты] были проверены после копирования параметров из компоновщика в объект и чтобы они проверялись в полях объекта, а не в полях компоновщика (элемент 39).

Если вы перейдете к пункту 39 (стр. 185), вы увидите причину:

[Это] защищает класс от изменений параметров из другого потока во время «окна уязвимости» между временем проверки параметров и временем их копирования.

Поля в Widget являются неизменяемыми и не требуют защитного копирования, но, тем не менее, безопаснее просто придерживаться правильного шаблона, если кто-то придет и добавит Date или массив или какой-либо изменяемый Collection позже. (Он также защищает от другого потока, изменяющего Builder в середине вызова на build(), но это довольно узкое окно безопасности, поэтому лучше всего просто убедиться, что Builder s не разделены между потоками. )

Более блохоподобная версия будет:

public class Widget {
    public static class Builder {
        private String name;
        private String model;
        private String serialNumber;
        private double price;
        private String manufacturer;

        public Builder( String name, double price ) {
            this.name = name;
            this.price = price;
        }

        public Widget build() {
            Widget result = new Widget(this);

            // *Post*-creation validation here

            return result;
        }

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

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

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

    private final String name;
    private final String model;
    private final String serialNumber;
    private final double price;
    private final String manufacturer;

    /**
     * Creates an immutable widget instance.
     */
    private Widget( Builder b ) {
        this.name = b.name;
        this.price = b.price;
        this.model = b.model;
        this.serialNumber = b.serialNumber;
        this.manufacturer = b.manufacturer;
    }

    // ... etc. ...
}

Все поля Widget теперь final, и все они проверяются после создания.

11 голосов
/ 01 февраля 2011

Шаблон GoF фокусируется на абстрагировании этапов построения, так что, изменяя компоновщик, вы можете получить разные результаты, в то время как «пересмотренный компоновщик» нацелен на проблему ненужной сложности, добавляемую несколькими конструкторами.Таким образом, паттерн GoF больше относится к абстракции, а исправленный паттерн - больше к простоте (IMO).

Посмотрите на примеры в http://en.wikipedia.org/wiki/Builder_pattern и http://rwhansen.blogspot.com/2007/07/theres-builder-pattern-that-joshua.html, и это должно быть совершенно ясно.

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