Why would I ever use a Chain of Responsibility over a Decorator?

31,054

Solution 1

The fact that you can break the chain at any point differentiates the Chain of Responsibility pattern from the Decorator pattern. Decorators can be thought of as executing all at once without any interaction with the other decorators. Links in a chain can be thought of as executing one at a time, because they each depend on the previous link.

Use the Chain of Responsibility pattern when you can conceptualize your program as a chain made up of links, where each link can either handle a request or pass it up the chain.

When I used to work with the Win32 API, I would sometimes need to use the hooking functionality it provides. Hooking a Windows message roughly follows the Chain of Responsibility pattern. When you hooked a message such as WM_MOUSEMOVE, your callback function would be called. Think of the callback function as the last link in the chain. Each link in the chain can decide whether to throw away the WM_MOUSEMOVE message or pass it up the chain to the next link.

If the Decorator pattern had been used in that example, you would have been notified of the WM_MOUSEMOVE message, but you would be powerless to prevent other hooks from handling it as well.

Another place the Chain of Command pattern is used is in game engines. Again, you can hook engine functions, events, and other things. In the case of a game engine, you don't want to simply add functionality. You want to add functionality and prevent the game engine from performing its default action.

Solution 2

Chain

Avoid coupling the sender of a request to its receiver by giving more than one object a chance to handle the request. Chain the receiving objects and pass the request along the chain until an object handles it.

vs

Decorator

Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality.

I'd say its around the order in which things will happen. If you chain them, the will be called along the chain. With a decorator you're not guaranteed this order, only that additional responsibilities can be attached.

Solution 3

I'd say that a Chain of Responsibility is a particular form of Decorator.

Solution 4

Decorator is used when you want to add functionality to an object.

COR is used when one of many actors might take action on an object.

A particular Decorator is called to take an action, based on the type; while COR passes the object along a defined chain until one of the actors decides the action is complete.

COR might be used when there are multiple levels of escalation to different handlers -- for instance, a call center where the customer's value to the company determines if the call goes to a particular level of support.

Solution 5

Well I can think of 2 situations:

  • You don't have a core object, i.e. you don't know what to do with the request after it passed all the layers/filters. (something like an aspect like interceptor chains that don't really care where the request ends).
  • You need to selectively apply some pre or post processing to the request. Not in a general enhancement form as the decorator does. i.e. Filters may or maynot handle a specific request but adding a decorator always enhances your object with some functionality.

Can't think of any more right now, would love to hear more in this topic.

Share:
31,054
Abhishek
Author by

Abhishek

I have been a senior developer with a focus on architecture, simplicity, and building effective teams for over ten years. As a director at Surge consulting I was involved in many operational duties and decisions and - in addition to software development duties - designed and implemented an interview processes and was involved in community building that saw it grow from 20 to about 350 developers and through an acquisition. I was then CTO setting up a dev shop at working closely with graduates of a coding bootcamp on both project work and helping them establish careers in the industry. Currently a Director of Engineering at findhelp.org your search engine for finding social services. I speak at conferences, have mentored dozens of software devs, have written popular articles, and been interviewed for a variety of podcasts and publications. I suppose that makes me an industry leader. I'm particularly interesting in companies that allow remote work and can check one or more of the following boxes: Product companies that help people in a non-trite manner (eg I'm not super interested in the next greatest way to get food delivered) Product companies that make developer or productivity tooling Funded startups that need a technical co-founder Functional programming (especially Clojure or Elixir) Companies trying to do something interesting with WebAssembly

Updated on July 05, 2022

Comments

  • Abhishek
    Abhishek almost 2 years

    I'm just reading up on the Chain of Responsibility pattern and I'm having trouble imagining a scenario when I would prefer its use over that of decorator.

    What do you think? Does CoR have a niche use?

    • Mykola Golubyev
      Mykola Golubyev about 15 years
      please add kind of a task which you think is task for CoR but you solved it with decorator
    • Abhishek
      Abhishek about 15 years
      Sure, I need to complete an order and in some cases I need to print a bill. My decorator solution is to have a core OrderCompleter wrapped in a OrderCompletionPrintDecorator which applies the conditional logic and prints. Works just as well as any chain.
    • Son Do Lenh
      Son Do Lenh about 12 years
      Why couldn't you just have a method called "Print" inside OrderCompleter that can be used (or not) when you want (don't want) to print? In other words, I was wondering whether you could solve this task withOUT using any pattern at all? It doesn't seem to me like a complicated task with a real need for introducing abstraction and complexity. Or maybe what you said is just a oversimplified version of the problem.
    • Abhishek
      Abhishek about 12 years
      @SonDo It depends - but yes, it's an oversimplified version. The question is, where does the logic go about what makes something print? If it's a simple decision it could go right into OrderCompleter.Complete() but it could instead be something like this: "If the printing service responds to a ping and this order or a parent order has not been printed yet and the client placing the order does not integrate directly with our system."
  • Mykola Golubyev
    Mykola Golubyev about 15 years
    You can attach in different order, no?
  • Abhishek
    Abhishek about 15 years
    If we're talking from the POV of a class consumer you're absolutely correct, if we're talking from the POV of the class designer however, you can certainly guarantee this as much as a chain could.
  • Abhishek
    Abhishek about 15 years
    Ok, but my point is that you can use a decorator with just as much if not less effort. So why the heck even involve CoR?
  • Ragoczy
    Ragoczy about 15 years
    But a decorator is a different pattern -- with COR, the object is passed from actor to actor until one says that it's completed the action; with decorator, the action is going to be performed on one particular class's implementation.
  • dave1010
    dave1010 over 9 years
    The decorator only needs to know the interface, not any implementation.
  • HakunaMatata
    HakunaMatata almost 8 years
    One line explains everything
  • Rishi
    Rishi almost 7 years
    IMO In the CoR pattern, we can have many (or all) handler (link) objects could contribute to each request's handling / building a response.
  • Dipon Roy
    Dipon Roy over 6 years
    So you are saying it could be a replacement for a nested if...else statement, except there will no else section at the end?
  • jaco0646
    jaco0646 about 4 years
    @Rishi, it's easy to imagine that, but the GoF does not mention it. In their CoR pattern, each request is handled once or not at all.
  • jaco0646
    jaco0646 about 4 years
    @DiponRoy, yes, but, the critical point of the CoR pattern is the decoupling. In an if...else block the caller sees every branch. In a CoR the caller doesn't even know the chain exists.