Chapter12 Decorator
Chapter12 Decorator
Contents
12.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
12.4 Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
12.4.1 Tree . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
12.4.2 SalesTicket . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
12.5 Exercises . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
References . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
1
12.1 Introduction
The decorator pattern is used to extend the functionality of an object without changing
the physical structure of the object [2]. The extension is either in terms of elaborating
on the state of the object or in terms of behaviour. A combination of both state and
behaviour is also possible which implies that these extensions can be stacked on the
object and rather than using subclassing, which is a compile-time solution, the extensions
can be applied at runtime.
In the sections that follow, an overview of the structure of the decorator pattern will be
given along with an explanation of how the decorator can be applied. The two examples
presented will illustrate how the decorator can be implemented. The first example will
decorate the composite tree developed in Lecture note 14, while the second example will
show how decorations of a till slip can change how the till slip is structured.
12.2.1 Identification
Name Classification Strategy
Decorator Structural Delegation (Object)
Intent
Attach additional responsibilities to an object dynamically. Decorators provide a
flexible alternative to subclassing for extending functionality. ([1]:175)
12.2.2 Structure
2
12.2.3 Participants
Component
• interface for objects that can have responsibilities dynamically added to them
ConcreteComponent
Decorator
ConcreteDecoratorA
ConcreteDecoratorB
It is conceivable that a list may be decorated with the same concrete decorator more than
once, it is however not always practical. The order of the application of the concrete
3
decorator should also be independent of one another and the net effect should be the
same. The reason being that decorated objects should behave as if defined as a single
large object with all the additional responsibility embedded in it.
Composite
A Decorator can be seen as a Composite with only one component that has added
responsibility.
Strategy
The Strategy pattern changes the inner workings of an object while the Decorator
changes the looks.
12.4 Example
12.4.1 Tree
To decorate the BaseNode of the tree example presented in Chapter 11, the decorator
pattern is applied to the Tree and BaseNode classes as shown in Figure 3. Notice that
destructors have been added to the hierarchy in order to ensure that the decorator clears
the memory when the first object in the list goes out of scope. The destructors for the
classes Tree, BaseNode, BehaviourDecorator and StateDecorator are all defined as
virtual and an implementation with no statements is provided. The destructor of the
Decorator class deletes the instance referred to by the attribute component.
4
Figure 3: Decorating the Tree: showing only the decorator pattern
Both the print functions defined in the concrete decorator participants make calls to the
parent print function to ensure that all chained prints are executed. Sample implemen-
tations of the print functions are given.
void D e c o r a t o r : : p r i n t ( )
{
component−>p r i n t ( ) ;
}
void S t a t e D e c o r a t o r : : p r i n t ( )
{
c o u t << ” ! ” << c o l o u r << ”−” ;
Decorator : : print ( ) ;
c o u t << ” ! ” ;
}
void B e h a v i o u r D e c o r a t o r : : p r i n t ( )
{
addedBehaviour ( ) ;
Decorator : : print ( ) ;
}
5
Figure 4 shows how the Composite and Decorator design patterns can be used together.
It is now possible to decorate the composite participant, IntermediateNode, as well.
12.4.2 SalesTicket
This example illustrates how the decorator can be applied to change the “look” of a till
slip (also referred to as a sales ticket) and customise it for a particular situation. A
typical till slip has a header section where the name of the shop is printed, a body where
a list of purchases are given and a footer with some friendly message or information. The
basic functionality of the till slip is to provide the customer with the items listed in the
body of the slip. The shop name displayed in the header and the greeting printed in the
footer are “nice to have” and provide an individual identity for the till slip. These added
responsibilities can easily be included by decorating the till slip with a header and a footer
that is customisable for the particular shop.
Figure 5 presents the UML class diagram for the description of the till slip given above.
The class SalesTicket represents the ConcreteComponent participant of the design pat-
tern. SomeClass represents the Decorator participant and the classes Header1, Header2,
Footer1 and Footer2 the ConcreteDecorator participant. SalesOrder represents the client
for the design pattern.
Understanding how the pattern works can be tricky and therefore some coding aspects of
the pattern are highlighted, specifically how printTicket is implemented for the partici-
pating classes. The printTicket of the SalesTicket class prints the body of the till slip.
SomeClass first checks whether the Component has been decorated before it called the
relevant printTicket function for linked component. The functions for both the Header
6
Figure 5: Printing sales tickets with the decorator
classes must first print their message before passing the printing on to the next compo-
nent. The Footer classes do this in reverse to ensure that the relevant text is displayed
at the bottom of the till slip.
void S a l e s T i c k e t : : p r i n t T i c k e t ( )
{
cout<<”Cash S a l e T i c k e t ”<<e n d l ;
cout<<” L i s t o f i t e m s purchased ”<<e n d l ;
cout<<” Item ”<< ’ \ t ’<<” Quantity ”<< ’ \ t ’<<” P r i c e ”<<e n d l ;
// p r i n t t h e i t e m s o u t
cout<<”TOTAL: ”<<e n d l ;
}
void SomeClass : : p r i n t T i c k e t ( )
{
i f (myComp)
myComp−>p r i n t T i c k e t ( ) ;
}
void Header1 : : p r i n t T i c k e t ( )
{
cout<<”Welcome t o t he Crazy Zone ”<<e n d l ;
SomeClass : : p r i n t T i c k e t ( ) ;
}
7
void F o o t e r 1 : : p r i n t T i c k e t ( )
{
SomeClass : : p r i n t T i c k e t ( ) ;
c o u t << ” I t was a p l e a s u r e doing ” << ” b u s i n e s s with you ”<<e n d l ;
}
12.5 Exercises
1. Is it possible for the Composite design pattern to be restricted to build a list data
structure? Explain.
2. For the combination of the Decorator and Composite given in Figure 4, identify the
participants of both patterns.
3. In the sales ticket example given in Figure 5 it is possible to construct the concrete
classes using the default constructor. Doing so will cause memory problems within
the classes. Explain how you would go about to fix the problem.
References
[1] Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides. Design patterns :
elements of reusable object-oriented software. Addison-Wesley, Reading, Mass, 1995.