Почему я должен использовать цепочку ответственности над декоратором?

Я просто просматриваю шаблон Chain of Responsibility, и у меня возникли проблемы с представлением сценария, когда я предпочел бы его использовать decorator.

Как вы думаете? Использует ли CoR нишу?

Ответ 1

Тот факт, что вы можете разбить цепочку в любой точке, отличает шаблон "Цепь ответственности" от шаблона Decorator. Декораторы можно рассматривать как исполняющие все сразу без какого-либо взаимодействия с другими декораторами. Связи в цепочке можно рассматривать как выполняющие по одному, поскольку каждый из них зависит от предыдущей ссылки.

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

Когда я работал с API Win32, мне иногда приходилось использовать функциональные возможности подключения. Подключение сообщения Windows примерно соответствует шаблону "Цепь ответственности" . Когда вы подключаете сообщение, например WM_MOUSEMOVE, вызывается функция обратного вызова. Подумайте о функции обратного вызова в качестве последней ссылки в цепочке. Каждое звено в цепочке может решить, следует ли выбросить сообщение WM_MOUSEMOVE или передать его цепочке на следующую ссылку.

Если в этом примере был использован шаблон Decorator, вы были бы уведомлены о сообщении WM_MOUSEMOVE, но вы были бы бессильны, чтобы другие манипуляторы не могли его обработать.

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

Ответ 2

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

Ключевое отличие состоит в том, что декоратор добавляет поведение new, которое фактически расширяет исходный интерфейс. Это похоже на то, как нормальное расширение может добавлять методы, за исключением того, что "подкласс" связан только ссылкой, что означает, что можно использовать любой "суперкласс".

Шаблон COR может изменять существующее поведение, которое аналогично переопределению существующего метода с использованием наследования. Вы можете вызвать super.xxx(), чтобы продолжить "цепочку" или обработать сообщение самостоятельно.

Итак, разница тонкая, но пример декоратора должен помочь:

interface Animal
{
    Poo eat(Food food);
}

class WalkingAnimal implements Animal
{
    Animal wrapped;
    WalkingAnimal(Animal wrapped)
    {
        this.wrapped = wrapped;
    }

    Position walk(Human walker)
    {
    };

    Poo eat(Food food)
    {
      return wrapped.eat(food);
    }
}

class BarkingAnimal implements Animal
{
    Animal wrapped;
    BarkingAnimal(Animal wrapped)
    {
        this.wrapped = wrapped;
    }

    Noise bark()
    {
    };

    Poo eat(Food food)
    {
        bark();
        return wrapped.eat();
    }
}

код >

Вы можете видеть, что мы можем составить ходячее, лаящее животное... или фактически добавить способность лаять любому животному. Чтобы напрямую использовать это дополнительное поведение, нам нужно будет сохранить ссылку на декоратор BarkingAnimal.

Все BarkingAnimal также лают один раз перед едой, которая изменила существующую функциональность и поэтому похожа на COR. Но намерение - это не то же самое, что COR, то есть найти одно животное из многих, которое съест пищу. Цель здесь - изменить поведение.

Вы могли бы представить, что COR применяется, чтобы найти человека, который возьмет животное на прогулку. Это может быть реализовано как связанный список, например, chained выше или как явный список... или что-то еще.

Надеюсь, это достаточно понятно!

Джон

Ответ 3

Сеть

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

против

декоратор

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

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

Ответ 4

Я бы сказал, что цепочка ответственности - это особая форма Decorator.

Ответ 5

Decorator используется, когда вы хотите добавить функциональность к объекту.

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

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

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

Ответ 6

Ну, я могу думать о двух ситуациях:

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

Не могу сейчас думать, хотелось бы услышать больше в этой теме.

Ответ 7

декоратор

  • Decorator шаблон позволяет динамически добавлять поведение к отдельному объекту.

  • Он обеспечивает гибкую альтернативу подкласс для расширения функциональности. Несмотря на то, что он использует наследование, он наследует интерфейс Lowest Common Denominator (LCD).

UML-диаграмма для Decorator

UML-диаграмма для Decorator

Последствия:

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

Полезные ссылки:

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

Decorator_pattern из wikipedia

decorator от sourcemaking

Цепочка ответственности:

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

Диаграмма UML

введите описание изображения здесь

Этот шаблон более эффективен, если:

  • Более чем один объект может обрабатывать команду
  • Обработчик не известен заранее
  • Обработчик должен быть определен автоматически
  • Он пожелал, чтобы запрос был адресован группе объектов без явного указания его получателя.
  • Группа объектов, которые могут обрабатывать команду, должна быть указана динамическим способом.

Полезные ссылки:

Chain-of-responsibility_pattern из wikipedia

chain-of-responsibility-pattern от oodesign

chain_of_responsibility от sourcemaking

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

Ответ 8

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

В классической интерпретации элемента CoR, который обрабатывает запрос, ломается цепочка.

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

Ответ 9

  • ключевое слово 'extends' - статическое расширение.
  • Рисунок декоратора - динамическое расширение.
  • Шаблон цепочки ответственности - просто обработка командного объекта с помощью   набор объектов обработки и те объекты не знают друг друга.

Ответ 10

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

Ответ 11

Прочитав определение "Банда четырех", я не уверен, что есть реальная разница. (для удобства)

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

Википедия немного скрывает их, но некоторые из них произвольны.

  • Декоратор обычно реализуется как связанный список. Но я думаю, что слишком низкоуровневый, чтобы считаться "частью" шаблона.
  • Связность цепочки ответственности обрабатывает данные только в том случае, если это их ответственность; но определение ответственности и обработка данных являются частью поведения. Декораторы могут сделать это так же легко.
  • Decorator требует, чтобы вы вызывали делегата.
  • "Чистая" ссылка CoR должна вызывать только делегат, если она не обрабатывает данные.

Первые два атрибута на самом деле не различают шаблоны. Во-вторых, но способ, которым обычно выполняются Decorator и CoR, не применяет эти атрибуты - дизайнер просто надеется, что никто не пишет Decorator, который разрушает цепочку или CoRLink, которая продолжает цепочку после обработки данных.

Чтобы реализовать эти атрибуты, вам нужно что-то вроде следующего.

Принудительный декоратор:

abstract class Decorated {

public Decorated delegate;

public final Object doIt(Object args) {
    Object returnVal = behavior(arg);
    if(delegate != null) returnVal = delegate.doit(returnVal);
    return returnVal;
}

protected abstract Object behavior(Object args); //base or subclass behavior
}

Принудительная цепочка ответственности:

abstract class Link {

public Link delegate;

public final Object processIt(Obect args) {
    Object returnVal = args;
    if(isMyResponsibility) returnVal = processingBehavior(returnVal);
    else returnVal = delegate.processIt(returnVal);
    return returnVal;
}

protected abstract Boolean isMyResponsibility(Object args);

protected abstract Object processingBehavior(Object args);
}

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