Click here to Skip to main content
Click here to Skip to main content

Deep Inside Structural Patterns :: Decorator Pattern :: Part 1

, 17 May 2014 CPOL
Rate this:
Please Sign up or sign in to vote.
New day, a new pattern. Today we will start to discuss structural patterns deeply starting with the Decorator pattern.

New day, a new pattern. Today we will start to discuss structural patternsdeeply starting with the Decorator pattern.

Really, I am trying to collect as many resources as possible for this huge topic to be valuable and to add something wasn’t published before so I am in parallel reading the famous book Gang of four, also C# 3.0 Design Patterns by O’Reilly, and some other tutorials and stuff.

I liked the way that O’Reilly book takes to discuss each pattern so I will reuse the headlines for each pattern but I will try to add more value to the content. So, let’s start discussing Decorator pattern.

1 – Role

Decorator pattern’s role is to provide a way to add new state and behavior dynamically. The decorated object doesn’t know that it is being decorated which is very useful for evolving systems.

2 – Illustration

As its name suggests, it is used to add or remove (decorate) objects at runtime with new state or new behavior. The best example that I have ever read to illustrate this pattern is the photo management system which lets you edit some aspects of the photo like adding new border, tag, or caption.

Consider we have a photo and we want to add a border to it, may be a border and caption, or may be caption only. If you just think a bit, you will find that a combination of photo and border makes another object which is photo with border. So every combination may result in a different (unknown) object at runtime which means we can have endless ways to customize the photo.

Also, I liked the illustration of the Gang of four book which is:

Suppose we have a TextView object that displays text in a window. TextView has no scroll bars by default, because we might not always need them. When we do, we can use a ScrollDecorator to add them. Suppose we also want to add a thick black border around the TextView. We can use a BorderDecorator to add this as well. We simply compose the decorators with the TextView to produce the desired result.

The beauty of this pattern is that:

  • The original object is unaware of any decorations.
  • There is no one big feature-laden class with all the options in it.
  • The decorations are independent of each other.
  • The decorations can be composed together in a mix-and-match fashion.

3 – Design

Reading here and there about this pattern, I have concluded that there are some minor variations in its design because of the language features you are implementing the pattern with. But the main guidelines remains.

I will start with a very general design (mentioned in the Gang of four book) then I will go through other variations step by step:

Basic Design

Players:

  1. ConcreteComponent
    • An original class of objects that can have operations added or modified (there may be more than one such class).
  2. Component
    • The base class that identifies the classes of objects that can be decorated (ConcreteComponent is one of these).
  3. Decorator
    • The base class that identifies the common operations or state in the decorator classes and it inherits from the Component base class.
  4. ConcreteDecorator
    • A class that inherits from the Decorator base class and adds state and/or behavior (there may be more than one such class).
  5. Operation
    • An operation in Component objects that can be replaced (there may be several operations).

Looking into the previous players, we will see that we have two base classes Component and Decorator. Most of the variations in this pattern’s design results from changing or replacing those two classes as we will see now.

Use this basic design if:

  1. You are not the creator of this object structure, like that you have already made structure and you want to decorate it.
  2. You are the one who creates this structure but your using C++ or any language doesn’t support interfaces.
  3. You have default implementation in both Decorator and Component base classes.
  4. You have multiple decorators have common behavior and/or state defined in Decorator base class.

Variation 1

As you notice from the previous diagram, you can see that we have replaced the Component base class with an interface IComponent. Here we have to mention that in old days when Gang of four book was written, authors had implemented the patterns using C++ which doesn’t contain interfaces. In modern languages today like C# or Java contain the concept of interfaces.

I recommend always to use interfaces not abstract classes as long as you don’t have default implementation you want to add for all the subclasses.

Use this variation if you are using a language contains the interfaces concept and:

  1. You don’t have any default implementation in the Component base class and you have default implementation for the all concrete decorators.
  2. You are the one who is creating this object structure from scratch and have full control of it.
  3. You have multiple decorators have common behavior and/or state defined in Decorator base class.

Variation 2

Use this variation if you are using a language contains the interfaces concept and:

  1. You don’t have any default implementation in both Component base class and Decorator base class.
  2. You are the one who is creating this object structure from scratch and have full control of it.
  3. You have multiple decorators have common behavior and/or state defined in the IDecorator interface.

C# 3.0 Design Patterns by O’Reilly notified that IDecorator in C# has no purpose. And I didn’t get this note until now, but I see that if you have common behavior and/or state that you want to be in all decorators then you have to use either interface or a base class and depending in your situation you can select what is more appropriate from the other variations.

Variation 3

Use this variation if you are using a language contains the interfaces concept and:

  1. You don’t have any default implementation in both Component base class and Decorator base class.
  2. You are the one who is creating this object structure from scratch and have full control of it.
  3. You don’t have common behavior and/or state between decorators.

Common Design Guidelines

As we saw in the last four variations, you will see some common guidelines that I want to concentrate on them:

  1. All components must have a base class or interface.
  2. All decorators must be components. In other words, all decorators must inherit Component base class or implement IComponent interface.
  3. All decorators must wrap a component (Decorator must have a member of type Component or IComponent).

4 – Implementation

I will try here to give you a simple implementation of the decorator pattern. I will discuss how to implement the decorator pattern in general without considering any challenging examples or complicated scenarios.

I will use variation 3 to give you a simple implementation using the following UML class diagram:

Using C# or another candidate language, First we have to create IComponent Interface which will contain only one operation.

1
2
3
4
public interface IComponent
{
void Operation();
}

Then we will create a Component class which will implement IComponent interface.

1
2
3
4
5
6
7
public class Component : IComponent
{
public void Operation()
{
Console.WriteLine("I love reading books.");
}
}

Now we want to decorate the Component object with a decorator. So let’s create one decorator class which will wrap an IComponent object and Implement the same interface IComponent interface.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class DecoratorA : IComponent
{
private IComponent _component;
public Decorator(IComponent component)
{
_component = component;
}
public void Operation()
{
_component.Operation();
Console.WriteLine("And I love playing football.");
}
}

Another decorator class:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class DecoratorB : IComponent
{
private IComponent _component;
public Decorator(IComponent component)
{
_component = component;
}
public void Operation()
{
_component.Operation();
Console.WriteLine("And I love fishing.");
}
}

Now let’s build the client which will be a simple console application which will consume our Component and will decorate it.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
using System;
namespace DecoratorPatternImplementation
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("=== Original Component ===");
IComponent component = new Component();
component.Operation();
Console.WriteLine();
Console.WriteLine("=== Original Component Decorated by DecoratorA ===");
IComponent decoratorA = new DecoratorA(component);
decoratorA.Operation();
Console.WriteLine();
Console.WriteLine("=== Original Component Decorated by DecoratorB ===");
IComponent decoratorB = new DecoratorB(component);
decoratorB.Operation();
Console.WriteLine();
Console.WriteLine("=== Decorated Component By DecoratorA Decorated by DecoratorB ===");
IComponent hybridDecorator = new DecoratorB(decoratorA);
hybridDecorator.Operation();
Console.WriteLine();
}
}
}

Run the console application and here is the output:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
=== Original Component ===
I love reading books.
=== Original Component Decorated by DecoratorA ===
I love reading books.
And I love playing football.
=== Original Component Decorated by DecoratorB ===
I love reading books.
And I love fishing.
=== Decorated Component By DecoratorA Decorated by DecoratorB ===
I love reading books.
And I love playing football.
And I love fishing.
Press any key to continue . . .

We have to point out to some important notices here:

  1. You can decorate a decorated component as we have seen in last example.
  2. Decorator pattern gives you the ability to mix and match between decorators.
  3. Decorators do not need any advanced language features; they rely on object aggregation and interface implementation.

5 – Finally

We are now ready to go deeply into this pattern by investigating some real world examples. Keep up, wait for the next article.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Ahmed Abdul Moniem
Architect
Egypt Egypt
Graduated at Ain-Shams University, Faculty of Engineering, Computers and Systems Department since 2006.
 
Experienced Software Engineer who is developing, training and leading development teams to build flexible, maintainable, and easy to use Internet/Intranet applications using latest technologies like C# .NET, ASP.NET, ASP.NET AJAX, MVC, jQuery, Umbraco, SQL Server and others.
 
My career objective is to provide quality solutions to complex business problems within scope using latest Microsoft technologies. Extensive experience in .NET programming, databases and technical communication. Flexible as regards moving from project to project and in assimilating new technologies.
 
Proven team leadership skills. And now looking to continue making a significant contribution within design and development / leading a technical team or consultancy role in my current position and the next ones.
 
Simply, I would like to be a .NET GURU.
 
My best achievement is to solve business problems to mankind using my programming skills which I am already doing like eating and drinking.
 
But the best one is when you save more than 200,000 EGP per month after deploying your software in an organization! That was in ISI when we save a lot of money, work and hassle after transforming very critical procedures processed by a very poor manual paper system to a very efficient paperless one just using a browser, a keyboard, and a cup of coffee!
Follow on   Twitter   LinkedIn

Comments and Discussions

 
GeneralMy vote of 3 PinmemberKlaus Luedenscheidt17-May-14 17:20 
GeneralRe: My vote of 3 PinprofessionalAhmed Abdul Moniem19-May-14 8:21 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web01 | 2.8.141022.1 | Last Updated 17 May 2014
Article Copyright 2014 by Ahmed Abdul Moniem
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid