Builder Vs Decorator pattern

Из Когда вы будете использовать шаблон Builder?,

Говорят, что шаблон компоновщика подходит для примера Pizza.

Почему не Decorator? путем обработки Сыра, Пепперони, Бэкона в качестве дополнительных украшений на базовой пицце.

Это по той причине, что Сыр/Пепперони нужно строить отдельно. Я не думаю, что их нужно строить отдельно, поскольку они могут быть доступны для чтения.

Прояснить Pls. Я также ищу хороший реальный образец декоратора и причину, почему он подходит для этого конкретного примера. Спасибо.

Ответ 1

Из статьи с рисунком декоратора wikipedia:

В объектно-ориентированном программировании узор декоратора - шаблон дизайна что позволяет новое/дополнительное поведение для добавления к существующему объекту динамически.

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

Другими словами, шаблон Builder позволяет легко построить объект, который расширяется в независимых направлениях во время построения, в то время как шаблон Decorator позволяет добавлять расширения к функциональности объекту после времени построения. Использование шаблона декоратора для построения объектов является плохим, потому что оно оставляет объект в несогласованном (или, по крайней мере, некорректном) состоянии до тех пор, пока не будут созданы все необходимые декораторы - аналогично проблеме JavaBean, использующей сеттеры для указания необязательных аргументов конструктора.

Ответ 2

Вы смешиваете две разные вещи. GoF классифицирует Builder как шаблон создания, а Decorator - структурный шаблон. Они описываются следующим образом (Gamma et al, стр. 1):

Builder (97) Отделить построение сложного объекта от его представления, чтобы тот же процесс построения мог создавать разные представления.

Decorator (175) Прилагайте дополнительные обязанности к объекту динамически. Декораторы обеспечивают гибкую альтернативу подклассу для расширения функциональности.

Обратите внимание на акцент на декораторе. Это гибкая альтернатива подклассу. Подклассификация используется для моделирования отношения is-a. Сыр - это не пицца. Пицца состоит из ряда ингредиентов, и это обычно моделируется с использованием композиции.

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

Чтобы принять реальный пример декоратора, я недавно хотел записать запросы, выполняемые с помощью jdbc в моем приложении java. Я выполнил это, выполнив класс LoggingConnection, который расширил интерфейс Connection.

public class LoggingConnection implements Connection
{
    public static class LogEntry
    {
        public String sql;
        public int invocationCount;
        public double avgTime;
        public double maxTime;
    }

    private Connection delegate;

    private Map<String, LogEntry> log;

    public LoggingConnection(Connection delegate)
    {
        this.delegate = delegate;
        this.log = new HashMap<String, LogEntry>();
    }

    public Map<String, LogEntry> getLog()
    {
        return log;
    }

    @Override
    public void clearWarnings()
    throws SQLException
    {
        delegate.clearWarnings();
    }

    @Override
    public void close()
    throws SQLException
    {
        delegate.close();
    }

    // forwarding declarations to all other methods declared in the interface
    ...
}

Это позволяет мне передать конкретную реализацию соединения и расширить его функциональность во время выполнения. В этом контексте подкласс будет проблематичным, потому что вы не обязательно знаете, какой объект подключения фактически возвращается. Это связано с тем, что он создан для вас с помощью DriverManager factory:

Connection conn = DriverManger.getConnection(dsn);

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

Ответ 3

Давайте рассмотрим ключевые характеристики Builder и Decorator.

Builder: (шаблон создания)

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

Decorator: (Структурный рисунок)

  • Добавить поведение объекта во время выполнения. Наследование - это ключ к достижению этой функциональности, что является одновременно преимуществом и недостатком этого шаблона.
  • Это улучшает поведение интерфейса.
  • Декоратор можно рассматривать как вырожденный композит с одним компонентом. Тем не менее, Decorator добавляет дополнительные обязанности - он не предназначен для агрегации объектов.
  • Декоратор поддерживает рекурсивную композицию
  • Decorator предназначен для добавления обязанностей к объектам без подкласса

Когда использовать Decorator:

  • Обязанности и поведение объекта должны динамически добавляться/удаляться
  • Конкретные реализации должны быть отделены от обязанностей и поведения
  • Когда подклассификация слишком дорогостоящая, чтобы динамически добавлять/удалять обязанности

Возвращаясь к вашему запросу:

Builder - это правильный шаблон создания для Pizza. Сначала пицца создается с обязательными ингредиентами (Хлеб и т.д.). Сыр, Пепперони, Бэкон являются необязательными ингредиентами, но все же они могут быть частью пиццы во время процесса сборки.

Декоратор полезен для добавления динамических обязанностей во время выполнения для уже созданного объекта.

например.:

BufferedInputStream bis = new BufferedInputStream(new FileInputStream(new File("a.txt")));

Подробнее см. ниже:

Сохранение строителя в отдельном классе (свободный интерфейс)

Когда использовать шаблон декоратора?

Ответ 4

Рисунок построителя специально используется для сборки и Decorator для добавления специальных функций post build. например, в приведенном выше примере Pizza мы можем решить использовать один из двух шаблонов на основе проблемного домена.

Если Chilli Flakes необходимы для пиццы, и у нас есть много ингредиентов, чтобы добавить к Pizza, из которых немногие из них элементарны, чтобы сделать Pizza съедобным (значимым состоянием), мы можем предпочесть использовать Builder. Как только Пицца будет построена, мы можем позже пойти и украсить ее различными начинками, такими как томатный соус, маслины и т.д.

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