Thursday 13 September 2012

Design Patterns by Examples – Decorator Pattern


Design Patterns by Examples – Decorator Pattern

Introduction

This series of articles will help you to build a good understanding of design patterns using different examples from real life and some from well-known frameworks or APIs. There are many articles around the web that discuss design patterns but they sometimes lack appropriate examples to quote. So, either their purpose stays unclear or we cannot memorize the patterns longer and sooner they slip out of mind. More importantly, we understand them but to employ within our problem domain is again out of the quest.
Expert designers reuse solutions that they had worked on in the past and they re-engage them whenever they faced with the same problems. Rookie designers can also use design patterns to solve their problems efficiently. This article is intended to help both naive and expert developers by making them understand the application of patterns and opening up new dimensions in solutions domain.

Decorator Pattern

For the sake of continuity, let’s look at the formal definition first.
Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality.

At this stage you might not understand it clearly but as you go through the whole article you will gain better understanding of the pattern and would defiantly want to use it to solve your own domain problems.
In this part of the article I totally concerned about dynamic behaviors that most readers expect from pattern, decorator is not just design as well as analysis pattern too, we will discuss this in next part. So ignore NewState field in ConcreteDecoratorA for this time.

Problem Domain

To keep things simpler we take an example of a subsystem, where employees are working with different responsibilities (such as team members, team leads and a manager). A team member is responsible to do his assigned tasks and to coordinate with other members for the completion of group tasks. On the other hand, a team lead has to manage and collaborate with his team members and plan their tasks. Similarly, a manager has some extra responsibility over a team lead such as employee profiling, work assignment.
Following are the system entities and their behaviors:
Employee: calculate salary, join, terminate.
Team member: perform task, coordinate with others.
Team lead: planning, motivate.
Manager: assign task, employee profiling, create requirements.
There may be some other entities like Team, Task, etc. but my focus here is to convey the idea of a Decorator while keeping things simple and paying attention on root of pattern.

Traditional Approach

In such a system, the most followed approach is to make an employee super class and extend it to all three classes. Even this is an object oriented approach but it has some drawbacks.
Whenever a team member becomes a team lead, we have to create a new object of team lead and the previous object that points to that employee (team member) may be destroyed or archived. That’s not a recommended approach when employee is still a part of your organization. Same is the case with manager, when an employee turns into a manager from a team lead/team member.
Another case is when an employee can perform responsibilities of a team member as well as those of a team lead or a manager can perform team leads responsibilities. In that case you need to create two objects for the same employee which is totally wrong.
In these scenarios a team member/team lead can have extra responsibilities at run time. And their responsibilities can be assigned/revoked at run time.

Decorator Pattern Approach

Let’s see how design patterns help in these cases. If we look at Decorator Pattern it says:
Attach additional responsibilities to an object dynamically.
Wow, can it really solve my problem, let’s see.
At this moment we defector our previous approach in such a way that we always register just an Employee and TeamMember, TeamLead andManager will be decorator of that employee object.
Now, if we want to change responsibilities of an employee to manager we just need a new Manager (Decorator) and assigning that employee to it will solve our problem. Same is the case when a team lead’s responsibilities are revoked, and some other member becomes team lead, we just need to swap employee objects within TeamMember and TeamLead decorators.
As for the case where an employee can perform the responsibilities of a team member as well as those of a team lead, we just need TeamMember andTeamLead decorators that are pointing to same employee object.

Employee (Decorated/Component)

Implementation of Employee is as follows:

public interface
 Employee {

public void join(Date joinDate); 
public void terminate(Date terminateDate);

// other behaviors may reside (see sample code)
}

EmployeeImpl

This is the core implementation class of Employee interface, EmployeeImpl is given below:

public class
 EmployeeImpl implements Employee { 


// other behaviors and properties may reside (see sample code)
public void join(Date joinDate){
print(this.getName() + ” joined on “ + joinDate);
}

public void terminate(Date terminateDate){
print(this.getName() + ” terminate on “ + terminateDate);
}
}

EmployeeDecorator (Abstract Decorator)

This is an abstraction of Employee decorator, EmployeeDecorator is given below:

public abstract class EmployeeDecorator implements Employee {

protected Employee employee;

protected EmployeeDecorator(Employee employee) {
this.employee = employee;
}

// other behaviors may reside (see sample code)

public void join(Date joinDate) {
employee.join(joinDate);
}

public void terminate(Date terminateDate) {
employee.terminate(terminateDate);
}
}

TeamMember/TeamLead/Manager (Concrete Decorator)

These are concrete implementations of EmployeeDecorator, classes are given below:

public class TeamMember extends EmployeeDecorator {

protected TeamMember(Employee employee) {
super(employee);
}

public void performTask() {
print(employee.getName() + ” is performing his assigned tasks.”);
}

public void coordinateWithOthers() {
print(employee.getName() + ” is coordinating with other members of his team.”);
}

}

public class TeamLead extends EmployeeDecorator {

protected TeamLead(Employee employee) {
super
(employee);
}


public void planing() {
print(this.employee.getName() + ” is planing.”);
}

public void motivate() {
print(this.employee.getName() + ” is motivating his members.”);
}

}

public class Manager extends EmployeeDecorator {

protected Manager(Employee employee) {
super
(employee);
}

public void assignTask() {
print(this.employee.getName() + ” is assigning tasks.”);
}

public void profileEmployee() {
print(this.employee.getName() + ” is profiling employees.”);
}

public void createRequirments() {
print(this.employee.getName() + ” is creating requirement documents.”);
}

}

Some Example from APIs

There are many application of decorator in our routine APIs, like in I/O Streams and Readers use decorator pattern extensively.
In this example FilterInputStream, BufferedInputStream, DataInputStream and PushbackInputStream are decorators and FileInputStream andByteArrayInputStream are decorated objects.

InputStream inStream = new FileInputStream(“data.txt”);
Here inStream is a simple file input stream and


inStream = new BufferedInputStream(inStream);
Now inStream is decorated by BufferedInputStream decorator. At runtime the BufferedInputStream, which is a decorator, forwards the method call to its decorated object FileInputStream. The decorator will apply the additional functionality of buffering around FileInputStream.
SiteMash is also one of the examples of decorator pattern in java web frameworks to decorate page.

Basic steps to use Decorator

To implement the decorator pattern you can just follow these steps:
  1. Create an abstract class or interface that you want to decorate. (e.g; Employee) and provide concrete implementation of that class/interface by extending it.
  2. Create an abstract decorator (e.g; EmployeeDecorator) that contains pointer field of decorated class, decorator must extend same decorated class/interface. (e.g; Employee)
  3. Pass the object that you want to decorate in the constructor of decorator.
  4. Redirect methods of decorator to decorated class’s core implementation.
  5. Override methods where you need to change behavior.

Conclusions

  • Decorators are very flexible alternative of inheritance.
  • Decorators enhance (or in some cases restrict) the functionality of decorated objects.
  • They work dynamically to extend class responsibilities, even inheritance does same but in a static fashion (means compile time).

Design Patterns

The key to any solution is to understand the problem. When we have complete requirements of our problem domain, the proper analyses of those requirements will facilitate us when incorporating any possible changes in the future. We have to suggest some design that can support current requirements and any possible changes. Therefor we use our past experience or shared thoughts of experts (Design Patterns) to design an elegant, flexible and reusable solution, and try to avoid redesigning or at least minimize it.

Design patterns are solutions to design problems you find again and again in real world application development.
Design patterns are not actually APIs that can be programmed in classes and reused as they are, neither are they are not domain-specific designs for any application or module. Design patterns actually are guidelines for communicating objects and classes that are customized to solve a general design problem in a particular context.

No comments:

Post a Comment