Зачем мне использовать цепочку ответственности над декоратором? - PullRequest
67 голосов
/ 14 апреля 2009

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

Что ты думаешь? Есть ли у CoR нишевое использование?

Ответы [ 11 ]

64 голосов
/ 14 апреля 2009

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

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

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

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

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

16 голосов
/ 29 августа 2009

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

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

Шаблон 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 выше, или в виде явного списка ... или чего-либо другого.

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

John

13 голосов
/ 14 апреля 2009

Сеть

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

против

декоратор

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

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

9 голосов
/ 14 апреля 2009

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

8 голосов
/ 14 апреля 2009

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

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

A частности Вызывается декоратор для выполнения действия в зависимости от типа; в то время как COR передает объект по определенной цепочке, пока один из действующих лиц не решит, что действие завершено.

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

4 голосов
/ 14 апреля 2009

Ну, я могу вспомнить 2 ситуации:

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

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

2 голосов
/ 05 апреля 2016

декоратор

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

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

UML-диаграмма для Декоратора

UML diagram for Decorator

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

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

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

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

Decorator_pattern из википедии

декоратор от создания источника

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

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

Диаграмма UML

enter image description here

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

  1. Команда может обрабатывать более одного объекта
  2. Обработчик заранее не известен
  3. Обработчик должен определяться автоматически
  4. Желательно, чтобы запрос был адресован группе объектов без явного указания получателя
  5. Группа объектов, которые могут обрабатывать команду, должна указываться динамически

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

Chain-of-ответственность_pattern из Википедии

образец цепи ответственности от oodesign

chain_of_responsibility от создания источника

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

1 голос
/ 24 января 2012
  1. ключевое слово 'extends' - статическое расширение.
  2. Шаблон декоратора - динамическое расширение.
  3. Шаблон Chain Of Responsibility - просто обработка объекта команды с набор объектов обработки и эти объекты не знают друг друга.
1 голос
/ 12 декабря 2010

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

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

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

0 голосов
/ 18 марта 2014

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

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

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

  • Декоратор обычно реализован в виде связанного списка. Но я думаю, что это слишком низкий уровень, чтобы считаться «частью» паттерна.
  • Ссылки Chain of Responsibility обрабатывают данные только в том случае, если это их ответственность; но определение ответственности и обработка данных являются частью поведения. Декораторы могут сделать это так же легко.
  • Декоратор требует, чтобы вы вызвали делегата.
  • «Чистая» ссылка 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, если все, что вам нужно, это освободить себя от ответственности в случае, если кто-то еще испортит ваш дизайн - но зачем оставлять это на волю случая?)

...