Home >
Overview
Purpose of this article
The goal of this article is to help you gain a better understanding of the Decorator design pattern. The Decorator pattern is used to attach additional responsibilities to an object at run time dynamically. Decorators provide a flexible alternative to subclassing to extend the functionality of classes in a hierarchical relationship. The Decorator design pattern utilizes an important OOP concept known as the open closed principal. This means that classes are open to extension but closed for modification. The Decorator pattern also uses the concept of composition, another very powerful OOP concept.
Design patterns are an awesome topic and the Decorator pattern is very powerful. Let’s continue exploring!
-Sean Moore, August 2009
Prerequisite knowledge
OOP fundamentals
A firm handle on basic OOP fundamentals is important to understanding this article. The Decorator design pattern uses core OOP concepts such as inheritance and composition.
OOP Links:
If you are not abreast in OOP basics you should take a moment to review the following material:
Object-oriented programming with ActionScript 3.0
http://www.adobe.com/devnet/actionscript/articles/oop_as3.html
Object Orientation
http://www.tricedesigns.com/tricedesigns_home/blog/2006/12/object-orientation.html
Lesson: Object-Oriented Programming Concepts
http://java.sun.com/docs/books/tutorial/java/concepts/
Decorator pattern examples
There is an example Flex project to going along with this article. The class diagrams have also been included for in the accompanying download.
This example demonstrates the Decorator pattern in practice. We’ll be building up a User class with several different configurations that different user types could possess.
Code example:
http://www.seantheflexguy.com/flex/insideria/DecoratorDesignPattern.zip
UML Diagrams:
http://www.seantheflexguy.com/flex/insideria/flex-decorator-uml-diagrams.zip
Decorator pattern concepts
Decorator pattern official definition:
Here is the definition of the Decorator design pattern from the Gang of Four’s book:
“Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality.” - Design Patterns: Elements of Reusable Object-Oriented Software
This definition begins to explain things but we’ll be taking a deeper look into the pattern in this article. Decorator is a good pattern to learn after learning the Strategy pattern. The Factory, Composite and Iterator are all great patterns to follow up the Decorator pattern with.
Core concepts and usage
The Gang of Four book describes three families of design patterns: creational patterns, structural patterns and behavioral patterns. The Decorator design pattern is a structural pattern.
“Structural patterns are concerned with how classes and objects are composed to form larger structures.” - Design Patterns: Elements of Reusable Object-Oriented Software
The Decorator pattern uses recursive composition to add layers of functionality to objects. Composition is a very important OOP concept to understand. Inheritance is a great way to build class hierarchies however it isn’t always the best or only solution. If implemented incorrectly or without taking a moment to consider all of the possible objects that can be born you create the opportunity for a class explosion. A multitude of classes created using inheritance can become a gigantic maintenance nightmare. The Decorator pattern can help prevent this problem from happening by using composition over inheritance.
A Decorator class follows the rules defined by the interface of the object it is enhancing. In doing so the objects that use the decorator aren’t aware that it is not truly an instance of the class being decorated. The decorator class passes along method calls to the class it’s enhancing. This approach enables a very flexible structure that permits an infinite amount of functionality that can be added to the class being decorated. Additional functionality can be added that isn’t tied to the decorated classes interface. You can supply various Decorators to Component classes to mix and match functionality.
Open Closed Principle
The Decorator Design pattern uses what’s known as the Open Closed Principle. This concept states that classes should be open for extension but closed for modification. In the decorator pattern composition is used to achieve this functionality. The decorator classes store an instance of the class they are decorating and forward method calls to that instance. The decorator adds more functionality as needed without having to modify the code of the instance it’s holding. This is a powerful concept that prevents from having to make changes to the class the decorator holds. Making changes to the class could potentially cause issues for a codebase that has already been tested and released. Utilizing the Open Closed Principle can help prevent ramifications from making such changes.
More information can be found here:
http://en.wikipedia.org/wiki/Open/closed_principle
Applicability
The Decorator pattern can be utilized in the follow scenarios:
- Attach functionality to individual objects dynamically and transparently.
- Add functionality to classes that can be removed.
- Prevent class explosion.
Core pattern diagram
The Decorator pattern can be seen below in its purist form. This is the design pattern with no implementation. This is basically the same diagram that is presented in the GoF book. It may help to review the concrete implementations of the pattern presented in this article and then return to review the core pattern diagram to understand the abstract concept.
Pattern participants
Here is a quick overview of the main participants of the Decorator design pattern:
- Component
The interface for objects that dynamically have new functionality added to them
- ConcreteComponent
An object that new functionality can be attached
- Decorator
Stores a reference to a Component object and mirrors the Component classes interface
- ConcreteDecorator
Builds additional functionality on top of the Component class
Flex Decorator design pattern example
Sample Decorator pattern implementation
To gain a better understanding of a pattern it’s often a good idea to create a code example. The accompanying code example is simple yet practice on a very basic level. It doesn’t deal with fruit, or animals or cars. Just keep in mind this is a very basic example that will hopefully shed some light on the underlying concepts used by the pattern.
The example adds different types of web hosting options to a base web hosting plan and calculates a total price depending on what services have been added on top of the base plan. Hopefully this concept is familiar enough to make sense without distracting from the design pattern concepts being explained.
Sample Decorator classes
This example is made up of the following classes:
- DecoratorDesignPattern
Creates the instance of the Order class and decorates it with instances of different types of hosting services.
- IOrder
Defines the contract that implementing classes such as Order must follow. The abstract decorator and Order classes implement the IOrder interface. Other objects that use Order objects or concrete decorators don’t know the difference between an Order and a decorated Order.
- Order
A concrete implementation of the IOrder interface that will be decorated with the various hosting service classes.
- AbstractOrderDecorator
Provides the basic functionality for the concrete decorator objects.
- BasicHostingServiceCost
Provides functionality and pricing details for the basic hosting service decorator.
- FlashMediaServerHostingServiceCost
Provides functionality and pricing details for the Flash Media Server hosting service decorator.
- MySQLHostingServiceCost
Provides functionality and pricing details for the MySQL hosting service decorator. This class adds additional functionality to add databases to the account and increase the hosting cost accordingly.
- SubversionHostingServiceCost
Provides functionality and pricing details for the Subversion hosting service decorator.
Running the Decorator Design Pattern example
When the Decorator Design Pattern example is launched an Order is created and various services are added to the base hosting account increasing the cost. Trace statements are executed sending messages to the Output window showing the services being added and the price being increased for each service.
The IOrder Interface
Here is the contract that defines all Order objects. This interface is pretty straight forward. It defines two methods that all implementing classes must have. Consequently the abstract decorator and decorator implementations will also follow this contract.
package com.seantheflexguy.insideria.dp.decorator
{
public interface IOrder
{
function calculateTotal() : Number
function getBilledServices() : String
}
}
The concrete Order class
Here is the concrete implementation of the Order class.
package com.seantheflexguy.insideria.dp.decorator
{
public class Order implements IOrder
{
public function Order()
{
}
public function calculateTotal() : Number
{
return 0;
}
public function getBilledServices() : String
{
return "Billed services: ";
}
}
}
The AbstractDecorator class
Here is the code for the abstract representation of a web hosting service decorator.
package com.seantheflexguy.insideria.dp.decorator
{
public class AbstractOrderDecorator extends Order
{
protected var order : Order;
public function AbstractOrderDecorator()
{
}
override public function calculateTotal() : Number
{
return order.calculateTotal();
}
override public function getBilledServices() : String
{
return order.getBilledServices();
}
}
}
The BasicHostingServiceCost class
Here is the concrete implementation for the basic hosting service cost class.
package com.seantheflexguy.insideria.dp.decorator
{
public class BasicHostingServiceCost extends AbstractOrderDecorator
{
private var serviceName : String;
private var totalCost : Number;
public function BasicHostingServiceCost( order : Order )
{
this.order = order;
totalCost = 3.99;
serviceName = "Basic Hosting";
}
override public function calculateTotal() : Number
{
return order.calculateTotal() + totalCost;
}
override public function getBilledServices() : String
{
return order.getBilledServices() + serviceName;
}
}
}
The SubversionHostingServiceCost class
Here is the concrete implementation for the subversion hosting service cost class.
package com.seantheflexguy.insideria.dp.decorator
{
public class SubversionHostingServiceCost extends AbstractOrderDecorator
{
private var serviceName : String;
private var totalCost : Number;
public function SubversionHostingServiceCost( order : Order )
{
this.order = order;
totalCost = 5.99;
serviceName = "Subversion Hosting";
}
override public function calculateTotal() : Number
{
return order.calculateTotal() + totalCost;
}
override public function getBilledServices() : String
{
return order.getBilledServices() + ", " + serviceName;
}
}
}
The FlashMediaServerHostingServiceCost class
Here is the concrete implementation for the Flash Media Server hosting service cost class.
package com.seantheflexguy.insideria.dp.decorator
{
public class FlashMediaServerHostingServiceCost extends AbstractOrderDecorator
{
private var totalCost : Number;
private var serviceName : String;
public function FlashMediaServerHostingServiceCost( order : Order )
{
this.order = order;
totalCost = 19.99;
serviceName = "Flash Media Server Hosting";
}
override public function calculateTotal() : Number
{
return order.calculateTotal() + totalCost;
}
override public function getBilledServices() : String
{
return order.getBilledServices() + ", " + serviceName;
}
}
}
The MySQLHostingServiceCost class
Here is the concrete implementation for the MySQL hosting service cost class.
package com.seantheflexguy.insideria.dp.decorator
{
public class MySQLHostingServiceCost extends AbstractOrderDecorator
{
private var databaseCount : int;
private var serviceName : String;
private var _totalCost : Number;
public function MySQLHostingServiceCost( order : Order )
{
this.order = order;
totalCost = 9.99;
serviceName = "MySQL Hosting";
databaseCount = 1;
}
override public function calculateTotal() : Number
{
return order.calculateTotal() + totalCost;
}
override public function getBilledServices() : String
{
return order.getBilledServices() +
", " + serviceName +
"(w/ " + databaseCount +
" databases)";
}
public function get totalCost() : Number
{
return this._totalCost * databaseCount;
}
public function set totalCost( newCost : Number ) : void
{
this._totalCost = newCost;
}
public function addMySQLDatabases( databaseCount : int ) : void
{
this.databaseCount += databaseCount;
}
}
}
Exploring the DecoratorDesignPattern MXML file
This is a runnable Flex application that pulls the pieces of the Decorator pattern together.
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
creationComplete="init();">
<mx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
import com.seantheflexguy.insideria.dp.decorator.BasicHostingServiceCost;
import com.seantheflexguy.insideria.dp.decorator.FlashMediaServerHostingServiceCost;
import com.seantheflexguy.insideria.dp.decorator.MySQLHostingServiceCost;
import com.seantheflexguy.insideria.dp.decorator.Order;
import com.seantheflexguy.insideria.dp.decorator.SubversionHostingServiceCost;
private function init() : void
{
var order : Order = new Order();
order = new BasicHostingServiceCost( order );
trace( order.getBilledServices() + ": " + order.calculateTotal() );
order = new SubversionHostingServiceCost( order );
trace( order.getBilledServices() + ": " + order.calculateTotal() );
order = new FlashMediaServerHostingServiceCost( order );
trace( order.getBilledServices() + ": " + order.calculateTotal() );
order = new MySQLHostingServiceCost( order );
trace( order.getBilledServices() + ": " + order.calculateTotal() );
MySQLHostingServiceCost( order ).addMySQLDatabases( 1 );
trace( order.getBilledServices() + ": " + order.calculateTotal() );
MySQLHostingServiceCost( order ).addMySQLDatabases( 1 );
trace( order.getBilledServices() + ": " + order.calculateTotal() );
}
]]>
</mx:Script>
</mx:Application>
First the application creates an Order object. Next a Subversion account is added ad then a Flash Media Server account is added to the order. Finally a MySQL account is added to the account and then two additional MySQL databases are added to the MySQL service. The price is being updated according to pricing information inside of each decorator class. The final output of the application is as follows:
Billed services: Basic Hosting: 3.99
Billed services: Basic Hosting, Subversion Hosting: 9.98
Billed services: Basic Hosting, Subversion Hosting, Flash Media Server Hosting: 29.97
Billed services: Basic Hosting, Subversion Hosting, Flash Media Server Hosting, MySQL Hosting(w/ 1 databases): 39.96
Billed services: Basic Hosting, Subversion Hosting, Flash Media Server Hosting, MySQL Hosting(w/ 2 databases): 49.95
Billed services: Basic Hosting, Subversion Hosting, Flash Media Server Hosting, MySQL Hosting(w/ 3 databases): 59.94
Review
Putting it all together
The Decorator Design pattern is very powerful and helps to reiterate the concept of composition over inheritance. Inheritance relationships are not always the best solution and this pattern help facilitate a means to add functionality to a class without requiring all classes that extend it to have specialized methods that don’t apply to the inheriting class. The Decorator Design pattern is used for UI components in other languages to add scrollbars and border s to components. In the GoF book the sample illustrates how a text field component can be decorated with a scrollbar. Not all text will scroll so why embed the logic to handle scrollbars into the text field? This is the same concept that’s shown in the example for this article. Favor composition over inheritance and forward the method calls an instance of the class that’s being enhanced or decorated.
Summary
I hope this article has given an insight to the power of the Decorator pattern and opened the window to using more design patterns in your application development process. Codebases that take advantage of design patterns are often easier to update and maintain and they are also more scalable to future change. Definitely take a moment to review the sample applications and review the UML diagrams as well. This article combined with the diagrams and code examples should allow you to begin using the Decorator pattern in your work.
Additional Information
Web:
Decorator pattern
Wikipedia
http://en.wikipedia.org/wiki/Design_Patterns
Decorator UML diagram - GoF version
http://www.tml.tkk.fi/~pnr/GoF-models/html/Decorator.html
Books:
Design Patterns: Elements of Reusable Object-Oriented Software
Addison-Wesley Professional - Erich Gamma, Richard Helm, Ralph Johnson, John M. Vlissides
http://www.informit.com/store/product.aspx?isbn=0201633612
Head First Design Patterns
O'Reilly Media, Inc.: Eric Freeman, Elisabeth Freeman, Kathy Sierra, Bert Bates
http://oreilly.com/catalog/9780596007126/
ActionScript 3.0 Design Patterns
O'Reilly Media, Inc.: William B. Sanders, Chandima Cumaranatunge
http://oreilly.com/catalog/9780596528461/
Refactoring to Patterns
Addison-Wesley Professional: Joshua Kerievsky
http://www.informit.com/store/product.aspx?isbn=0321213351






Facebook Application Development
A simple example I use all the time of the Decorator Pattern is to wrap objects in a class that implements IUID so that the same object can appear multiple times in a List based control without confusing Flex.
They are also offering free website hosting for their customers. This website also helps you to create your own blog. They are also providing the website building tools. These website building tools will be more helpful for the beginners.
Very cool article.
A good way to learn decorator pattern, thank you sean
Hi, i'm always glad when someone investigate d.p. I would like to see more of them! The uml diagram is only a jpp or is originated from some some software? Thank you.
Excellent Article...Thanks for sharing Sean
Sweet.
A nice refresher and using AS3 :)
Thank you for reminding me of the beauty of the decorator pattern, well written and easy to follow.
-cheers-