Decorator pattern versus sub classing

24,865

Solution 1

from Decorator pattern at wikipedia

The decorator pattern can be used to make it possible to extend (decorate) the functionality of a certain object at runtime.

The whole point of decorator pattern is to dynamically add additional behaviour/functionality, which is of course not possible at design time.

from the same article:

The decorator pattern is an alternative to subclassing. Subclassing adds behavior at compile time, and the change affects all instances of the original class; decorating can provide new behavior at runtime for individual objects.

Solution 2

An example from GoF:

Suppose you have a TextView class. Then in someplace you want a scrolled text view, so you subclass TextView and create ScrolledTextView class. And in some other place, you want a border around text view. So you subclass again and create BorderedTextView. Well, now in someplace you want border and scroll both. None of the previous two subclasses have both capabilities. So you need to create a 3rd one. When creating a ScrolledBorderedTextView you are actually duplicating the effort. You don't need this class if you have any way to compose the capability of the previous two. Well, things can go worse and these may lead to an unnecessary class explosion.

Basically, by using the decorator pattern you can add any number of additional responsibility to object at RUNTIME which you can not achieve by subclassing without potentially damaging your code structure or adding many duplicate combinations for subclasses.

But one thing, Design patterns are not something that you must use.
Whether a pattern is needed or not is dependent on your particular problem, you want to maintain the code for a long time or not, whether you want to extend or not and on many other factors like these.
And there is no pattern that is useful in all cases.
A pattern (decorator or anything else) suitable for a situation may not be a good choice for another situation.

Solution 3

The GoF Design Patterns book identifies two major advantages of using Decorators over subclassing:

  1. More flexibility than static inheritance. The Decorator pattern provides a more flexible way to add responsibilities to objects than can be had with static (multiple) inheritance. With decorators, responsibilities can be added and removed at run-time simply by attaching and detaching them. In contrast, inheritance requires creating a new class for each additional responsibility (e.g., BorderedScrollableTextView, BorderedTextView). This gives rise to many classes and increases the complexity of a system. Furthermore, providing different Decorator classes for a specific Component class lets you mix and match responsibilities.

    Decorators also make it easy to add a property twice. For example, to give a TextView a double border, simply attach two BorderDecorators. Inheriting from a Border class twice is error-prone at best.

  2. Avoids feature-laden classes high up in the hierarchy. Decorator offers a pay-as-you-go approach to adding responsibilities. Instead of trying to support all foreseeable features in a complex, customizable class, you can define a simple class and add functionality incrementally with Decorator objects. Functionality can be composed from simple pieces. As a result, an application needn't pay for features it doesn't use. It's also easy to define new kinds of Decorators independently from the classes of objects they extend, even for unforeseen extensions. Extending a complex class tends to expose details unrelated to the responsibilities you're adding.

From my point of view, preventing subclass explosion alone is quite compelling.

If you have a TextWindow to which you want to add horizontal scrolling, vertical scrolling, and borders all independently and optionally, using subclasses, you'd have to define subclasses for HorizontalScrollingTextWindow, VerticalScrollingTextWindow, HorizontalAndVerticalScrollingTextWindow, BorderedTextWindow, HorizontalScrollingBorderedTextWindow, VerticalScrollingBorderedTextWindow, HorizontalAndVerticaScrollingBorderedTextWindow, and more if you care about the order of scrolling and bordering.

With Decorators, you only need to define two scrolling decorators and one border decorator.

Solution 4

Subclassing can lead to issues with the Liskov substitution principle. The decorator avoids this.

Another advantage of the decorator is that you are writing (forced to write) to an interface. This makes things easier for testing. It is true that your object hierarchy can also be written to an interface and thus have some of the same advantages, however, I can test a single implementation of a decorator class in isolation. I cannot do the same with a subclass because I will always get the whole hierarchy back to the base class. I am unable to test the new code in isolation.

Using the decorator pattern and following the single responsibility principle, I can create several decorators and stack them anyway I wish. I can configure that at runtime. In inheritance I either have to create every possible branch (a->b->c then a->c->b, thus duplicating code and exploding the number of tests), or I create 1 hierarchy then add another when needed, but this triggers a new test/release cycle.

This is why you would want to use the decorator pattern instead of subclassing.

Solution 5

Here is the differences based on the real implementation.

Decoration is an alternative way of sub classing to extend the functionality of existing classes. Here is some scenario where we should use sub classing or decorator.

1) Sub classing mainly used in the case of extend the functionality of similar group of classes which wants to retain the old functionality as well as new in the sub classes and all the instances of the sub classes share the same functionality. If we make the changes of child classes and then it will reflect all the instaces of child classes.Such as a hierarchy relation ship, similar group of classes.

Parent->Child->GrandSon.

Car->Maruti 800->Maruti 100( will have the feature of Maruti 800 as well as New)

2) Decorator pattern is used to decorate the existing classes without changing the old behavior.Such as a class circle have plain border but we need to decorate it with red border,after some time some user wants circle with yellow color and some user wants circle with green border and some user wants red and yellow border circle and some user wants red and green border circle etc,for this it is the perfect pattern as it will reduces no of combination classes.Below is the example.

Icircle cir=new RedDecorator(new circle()) decorating the circle with red color

Icircle cir=new YellowDecorator(new circle()) decorating the circle with Yellow color

Icircle cir=new RedDecorator(new YellowDecorator(new circle())) decorating the

circle with red and Yellow, here we do not need to create RedAndYellow class decorator. same way we can decorate the circle with other set of combination without creating new set of combination classes.

In this way it reduces the no of combination classes.

Here is the useful link for decorator pattern

https://www.tutorialspoint.com/design_pattern/decorator_pattern.htm

Share:
24,865
Gainster
Author by

Gainster

Updated on July 05, 2022

Comments

  • Gainster
    Gainster about 2 years

    I can solve the problem of adding functionality by adding sub classing then why should I use decorator pattern what's the real advantage of decorator pattern ?

  • Gainster
    Gainster over 13 years
    I have to create decorator classes at design too . So I in similar fashion I could add sub class so what's the point .
  • sloth
    sloth over 13 years
    the article at wikipedia provides some examples. Of course you have to do create the decorator classes at design time, put you can choose to apply them dynamically at runtime.
  • levininja
    levininja almost 10 years
    This is a good point...my initial thought was just to use interfaces for such classes, but those are not as modular/testable as having a decorator.
  • G. Demecki
    G. Demecki over 8 years
    @Gainster indeed, you're correct here. The biggest advantage of Decorator is a possibility of re-using such decorator for other classes. Exactly as other people stated in this thread.
  • nbilal
    nbilal over 6 years
    @Gainster There are many reasons why to prefer a decorator, among which, 1) You can reuse the same decorator on multiple implementations of the same interface (with inheritance you'll have to subclass every implementation), 2) You can test your decorator in isolation of the decorated object (not possible with inheritance to mock the parent class). Take a look at: dzone.com/articles/is-inheritance-dead