If you’re looking to extend the func­tion­al­it­ies of an existing class in object-oriented software, you have two choices. The easiest option is to implement sub-classes that com­ple­ment the base class. But this can be confusing. As an al­tern­at­ive, you can use a decorator entity according to the so-called decorator design pattern. The pattern, which is one of the 23 GoF design patterns, allows for a dynamic expansion of classes while the software is running. It works without endlessly long, difficult-to-un­der­stand in­her­it­ance hier­arch­ies.

Find out what exactly a decorator pattern is and what its ad­vant­ages and dis­ad­vant­ages are. In the following, we’ll also provide a graphic and an example to explain how this works.

What is the decorator pattern?

The decorator design pattern (decorator pattern in short) is a design strategy revealed in 1994 to expand the func­tion­al­ity of classes in object-oriented computer software. According to the pattern, any object can be expanded by a desired behaviour without in­flu­en­cing the func­tion­al­it­ies of other objects of the same classes. Struc­tur­ally, the decorator pattern resembles the ‘chain of re­spons­ib­il­ity’ pattern. But in contrast to the ‘chain of re­spons­ib­il­ity’ pattern, enquiries are being received by all classes via a central processor.

The software component that is to be expanded is ‘decorated’ according to the decorator design pattern. One or more decorator classes com­pletely enclose the component. Each decorator is of the same type as the enclosed component and, therefore, has the same interface. In this way, incoming method calls can be easily delegated to the linked component while a func­tion­al­ity is being carried out. Calls can also be directly processed within the decorator.

What’s the purpose of a decorator design pattern?

Much like other GoF patterns, for example the strategy pattern or the builder pattern, the decorator pattern aims to make com­pon­ents of object-oriented software more flexible and easier to reuse. To this end, the approach lets de­velopers add and remove de­pend­en­cies of an object dy­nam­ic­ally, and where necessary, during runtime. This makes the pattern a good al­tern­at­ive to using sub-classes. Sub-classes can sup­ple­ment a class, but do not allow for ad­just­ments to be made during runtime.

Note

A software component can be expanded with any number of decorator classes. These ex­ten­sions are invisible, which means one does not notice if an actual class is preceded by ad­di­tion­al classes.

Decorator pattern: UML diagram for visu­al­isa­tion

The decorator or decorator class (Con­crete­Dec­or­at­or) has the same interface as the software component to be decorated (Con­crete­Com­pon­ent) and is of the same type. This must be given to handle calls which are forwarded either unchanged or changed if the decorator doesn’t process them. Con­cep­tu­ally, the decorator pattern defines an ele­ment­ary interface – which is basically an abstract super class – as a ‘component’.

The in­ter­ac­tion between the basic component and the decorator is best il­lus­trated the form of a UML class diagram. Therefore, we’ve used the modelling language for object-oriented pro­gram­ming in a graphic, il­lus­trat­ing the decorator design pattern below.

The ad­vant­ages and dis­ad­vant­ages of the decorator patterns

Con­sid­er­ing the decorator design pattern when designing software pays off for several reasons. First and foremost, there is the high degree of flex­ib­il­ity when using the decorator structure: the func­tion­al­it­ies of classes can be expanded during the com­pil­a­tion and during runtime without the need for confusing in­her­it­ance-based class hier­arch­ies. This sig­ni­fic­antly improves the read­ab­il­ity of the program code.

Because func­tion­al­ity is split across multiple decorator classes, the per­form­ance of the software can be increased. This makes it easy to retrieve and initiate specific functions. With a complex base class that per­man­ently provides all functions, this resource-optimised option is not available.

However, de­vel­op­ment using the decorator pattern does have some dis­ad­vant­ages. Using the pattern increases the com­plex­ity of the software. The decorator interface, in par­tic­u­lar, usually contains a lot of code and is often linked to many terms, rendering it far from beginner friendly. Another dis­ad­vant­age is the large number of decorator objects, for which a separate sys­tem­at­isa­tion is re­com­men­ded to avoid similar overview problems when working with sub­classes. Long call chains of the decorated objects (i.e. the extended software com­pon­ents) make it harder to spot errors and debug in general.

Ad­vant­ages Dis­ad­vant­ages
High degree of flex­ib­il­ity High com­plex­ity of software (es­pe­cially decorator interface)
Expansion of function of classes without in­her­it­ance Not beginner-friendly
Readable program code High number of objects
Resource-optimised func­tion­al­it­ies Difficult debugging process

Decorator design pattern: typical use examples

The decorator pattern provides the basis for dynamic and trans­par­ent ex­pand­able objects of software. Com­pon­ents of graphic user in­ter­faces (GUIs) are common areas of ap­plic­a­tion of the pattern. For example, if a text field is to be framed, a decorator can be added ‘invisibly’ between the text field object and the call to insert the new interface element.

Well-known examples for the im­ple­ment­a­tion of the decorator design pattern are the so-called stream classes of the Java library, which are re­spons­ible for handling the input and output of data. Here, decorator classes are used to add new prop­er­ties and status in­form­a­tion to the data stream or to provide new in­ter­faces.

But Java is not the only pro­gram­ming language making wide­spread use of decorator patterns. The following pro­gram­ming languages also rely on the design pattern:

  • C++
  • C#
  • Go
  • JavaS­cript
  • Python
  • PHP

Practical examples for the im­ple­ment­a­tion of decorator patterns

The overview of ad­vant­ages and dis­ad­vant­ages of the decorator design pattern shows that it’s not suitable for all types of software. But where a class has to be modified sub­sequently and es­pe­cially in projects where this cannot be fa­cil­it­ated by using sub-classes, the design pattern is a great solution.

In this case, the starting point is software that makes the names of people ac­cess­ible via the abstract class ‘Employees’. However, the first letter of the retrieved names is always lowercase. Since a sub­sequent ad­just­ment is im­possible, the decorator class ‘Em­ploy­ee­Dec­or­at­or’ is im­ple­men­ted, which operates via the same interface and also enables the getName() method to be called. In addition, the decorator receives a logic to ensure the first letter is correctly cap­it­al­ised. The ap­pro­pri­ate code example looks like this:

public class EmployeeDecorator implements Person {
private Employee employee;
public Employee Decorator(Employee employee){
	this.employee = employee;
}
public String getName(){
	// call the method of employee class 
	String name = employee.getName();
	// Ensure first letter is capitalised
	name = Character.toUpperCase(name.charAt(0)) 
	+ name.substring(1, name.length());
	return name;
}
}
Go to Main Menu