Decorator Pattern vs Inheritance with examples

10,810

Solution 1

Suppose you create a View class that displays your items in a certain way. Now you decide you also want a version of it which is scrollable, so you create a ScrollableView which inherits the View. Later you decide you also want a version with a border so you now need to make a BorderedView and a BorderdScrollableView.

If on the other hand you could make a decorator for each added styling. You would have the following classes:

  • View
  • ScrollableDecorator
  • BorderedDecorator

When you want a bordered scroll view you do:

new BorderedDecorator(new ScrollableDecorator(new View())).

So you can configure any combination of this with just the 3 classes. And you can add or remove them at runtime (suppose you click a button that says add border, you now wrap your view with a BorderDecorator ... while whith inheritance you need to implemented this view class if you haven't already, or you need to create a new view instance and copy all relevant data from the first view to the second view which is not as easy to do as just adding or removing wrappers).

Solution 2

Imagine a game like Civilization, where each square on the map can have a variety of resources attached to it (like, say, various ores, or wood, or oil, etc.).

If you used straight inheritance, you'd need to create a class for each kind of square. It'd be unwieldy to have

public class OilSquare {}
public class OilAndGoldSquare {}
public class GoldAndSilverSquare {}
// etc.

The Decorator Pattern allows one to mix and match without needing to create a rigid hierarchy. So, you'd have instead:

public class Square {}
public class GoldDec {}
public class SilverDec {}
public class OilDec {}

// ...

var crazyMix = new GoldDec(new SilverDec(new OilDec(new Square())));

Put another way, Decorators allow for the creation of pipeline behavior, with each step in the pipeline being swappable with another step.

Solution 3

As others have already said Decorators are good for adding "options" to things... The benefits come in the way you can chain methods etc. through the decorators.

Imagine I buy a car with options for leather interior, metallic paint and awesome spoiler...

There are 8 different combinations of the three options but with decorators you only need three extra classes.

The interesting thing though is the way the decorator pattern works. As a brief example:

public class MetallicPaint : Car
{
    private Car car;
    public MetallicPaint(Car wrappedCar)
    {
        car = wrappedCar;
    }

    public decimal Cost()
    {
        return car.Cost() + 500;
    }

    public string Description()
    {
        return car.Description() + ", Metallic Paint";
    }
    public string Speed()
    {
        return car.Speed();
    }
    [... {pass through other methods and properties to the car object}]
}

This isn't a complete example but highlights how the decorator can interact with the object it is decorating. And of course because it implements car it can be used just like a car in every other way (and passes through anything the decorator doesn't effect to the inner car object).

Of course if you had multiple of these decorators with a car nested inside each would in turn add their cost, their part of the description and maybe the spoiler would alter the speed whereas the others didn't...

In essence it allows you to modify an object in a much more modular and less fundamental way than inheritance would. Decorators should always be used as if they were the base object (in this case Car) so they should never expose any new methods or properties, just slightly change the effect of existing ones.

Solution 4

Decorator pattern is better than inheritance if you have many features to be added and you also require to have combination of these features. Suppose your base class is A, and you want to extend(decorate) this base class with feature f1,f2,f3,f4 and some combination of them like (f1,f2) and (f1,f3) and .. ; so you would require to create 4!=4*3*2*1=24 class in your hierarchy (4 for each feature and the rest for their combination). While, Using decorative pattern, you would only need to create 4 classes!


for @Seyed Morteza Mousavi in @Razvi post: You are right, we can add two properties Scrollable and Bordered to View class, then check if the property is set to true so run the desired behaviour. But this requires that we already be aware of the number of the feature we require(which is not the case in decorator pattern). otherwise, with every new feature (say f1) we want to add to our class, we need to alter our main class, or inherit the main class (you would say) and add the property. Taking latter approach, you would further need to alter the part of the code which handles feature combination (this is not good, since it is not obeying the rule of thumb of "loose coupling!")

hope this helps.

Share:
10,810
Jon
Author by

Jon

Updated on June 15, 2022

Comments

  • Jon
    Jon about 2 years

    I've been experimenting with the decorator pattern to extend functionality of code you do not want to touch for example and I see how to implement it however I am now unsure why you don't just inherit from the original class and extend that way.

    I have read that the decorator pattern allows you to add functionality at runtime whereas inheritance means its there at compile time.

    I don't understand this.

    Could someone explain this, provide examples and explain when its better to use decorator vs inheritance.

    Thanks