Design Patterns Tutorial
A tutorial on GOF design patterns. This tutorial is for beginners who are going to learn design patterns for the first time. Each pattern is expalined with suitable examples.
Subscribe to Startertutorials.com's YouTube channel for different tutorial and lecture videos.

Categories: Structural Patterns. No Comments on Decorator Pattern in Design Patterns a Java Example
0
(0)

Decorator pattern is used to attach additional responsibilities to an object dynamically. Decorator provides an alternative to subclassing for extending the functionality.

 

Decorator pattern’s Intent

To attach additional responsibilities to an object dynamically. Decorator provides an alternative to subclassing for extending the functionality.

 

Also Known As

Wrapper

 

Decorator pattern’s Motivation

Extending an object’s functionality can be done statically (at compile time) by using inheritance however it might be necessary to extend an object’s functionality dynamically (at runtime) as an object is used.


Subscribe to our monthly newsletter. Get notified about latest articles, offers and contests.


 

Consider the typical example of a graphical window. To extend the functionality of the graphical window for example by adding a frame to the window would require extending the window class to create a FramedWindow class. To create a framed window it is necessary to create an object of the FramedWindow class. However it would be impossible to start with a plain window and extend its functionality at runtime to become a framed window.

 

Decorator pattern’s Applicability

Use decorator:

  • To add additional responsibilities to individual objects dynamically and transparently, that is, without affecting other objects.
  • For responsibilities that can be withdrawn.
  • When extension by subclassing is impractical.

 

Decorator pattern’s Structure

The structure of decorator pattern is as shown below:

Decorator Pattern Structure

 

Participants

The participants in the decorator pattern are:

  • Component: Defines the interface for objects that can have responsibilities added to them dynamically.
  • ConcreteComponent: Defines an object to which additional responsibilities can be attached.
  • Decorator: Maintains a reference to a component object and defines an interface that conforms to Component’s interface.
  • ConcreteDecorator: Adds responsibilities to the component.

 

Collaborations

Decorator forwards requests to its component object. It may optionally perform additional operations before and after forwarding the request.

 

Decorator pattern’s Consequences

The decorator pattern has atleast two key benefits and two liabilities:

  1. More flexibility than static inheritance: The Decorator pattern providesa more flexible way to add responsibilities to objects than can be had withstatic (multiple) inheritance.

 

  1. Avoids feature-laden classes high up in the hierarchy: Decorator offersa pay-as-you-go approach to adding responsibilities. Instead of trying tosupport all foreseeable features in a complex, customizable class, you candefine a simple class and add functionality incrementally with Decoratorobjects.

 

  1. A decorator and its component aren’t identical: A decorator acts as atransparent enclosure. But from an object identity point of view, adecorated component is not identical to the component itself.

 

  1. Lots of little objects: A design that uses Decorator often results in systemscomposed of lots of little objects that all look alike. The objects differonly in the way they are interconnected, not in their class or in the valueof their variables.

 

Decorator pattern’s Implementation

Following issues should be considered when applying the decorator pattern:

  1. Interface conformance: A decorator object’s interface must conform to the interface of the component it decorates. ConcreteDecorator classes must therefore inherit from a common class.

 

  1. Omitting the abstract Decorator class: There’s no need to define an abstract Decorator class when you only need to add one responsibility.

 

  1. Keeping Component classes lightweight: To ensure a conforming interface, components and decorators must descend from a common Component class. It’s important to keep this common class lightweight; that is, it should focus on defining an interface, not on storing data.

 

  1. Changing the skin of an object versus changing its guts: We can think of a decorator as a skin over an object that changes its behavior. An alternative is to change the object’s guts. The Strategy (349) pattern is a good example of a pattern for changing the guts.

 

Sample Code (Java Example)

Suppose we want to implement different kinds of cars – we can create interface Car to define the assemble method and then we can have a Basic car, further more we can extend it to Sports car and Luxury Car. The implementation hierarchy will look like below image.

Decorator Pattern Sample Code

But if we want to get a car at runtime that has both the features of sports car and luxury car, then the implementation gets complex and if further more we want to specify which features should be added first, it gets even more complex. Now image if we have ten different kind of cars, the implementation logic using inheritance and composition will be impossible to manage. To solve this kind of programming situation, we apply decorator pattern.

 

We need to have following types to implement decorator design pattern:

 

Component Interface – The interface or abstract class defining the methods that will be implemented. In our case Car will be the component interface.

//Car.java
public interface Car {
 
    public void assemble();
}

 

Component Implementation – The basic implementation of the component interface. We can have BasicCar class as our component implementation.

//BasicCar.java
public class BasicCar implements Car {
 
    @Override
    public void assemble() {
        System.out.print("Basic Car.");
    }
 
}

 

Decorator – Decorator class implements the component interface and it has a HAS-A relationship with the component interface. The component variable should be accessible to the child decorator classes, so we will make this variable protected.

//CarDecorator.java
public class CarDecorator implements Car {
 
    protected Car car;
     
    public CarDecorator(Car c){
        this.car=c;
    }
     
    @Override
    public void assemble() {
        this.car.assemble();
    }
 
}

 

Concrete Decorators – Extending the base decorator functionality and modifying the component behavior accordingly. We can have concrete decorator classes as LuxuryCar and SportsCar.

//SportsCar.java
public class SportsCar extends CarDecorator {
 
    public SportsCar(Car c) {
        super(c);
    }
 
    @Override
    public void assemble(){
        car.assemble();
        System.out.print(" Adding features of Sports Car.");
    }
}

 

//LuxuryCar.java
public class LuxuryCar extends CarDecorator {
 
    public LuxuryCar(Car c) {
        super(c);
    }
     
    @Override
    public void assemble(){
        car.assemble();
        System.out.print(" Adding features of Luxury Car.");
    }
}

 

Decorator Pattern Sample Code Structure

 

Here is the client program:

//DecoratorPatternTest.java
public class DecoratorPatternTest {
 
    public static void main(String[] args) {
        Car sportsCar = new SportsCar(new BasicCar());
        sportsCar.assemble();
        System.out.println("\n*****");
         
        Car sportsLuxuryCar = new SportsCar(new LuxuryCar(new BasicCar()));
        sportsLuxuryCar.assemble();
    }
 
}

 

Decorator pattern’s Known Uses

Following are the examples in Java API where decorator pattern is used:

  • All subclasses of io.InputStream, OutputStream, Reader and Writer have a constructor taking an instance of same type.
  • util.Collections, the checkedXXX(), synchronizedXXX() and unmodifiableXXX() methods.
  • servlet.http.HttpServletRequestWrapper and HttpServletResponseWrapper

 

Related Patterns

Adapter: A decorator is different from an adapter in that a decorator only changes an object’s responsibilities, not its interface; an adapter will give an object a completely new interface.

 

Composite: A decorator can be viewed as a degenerate composite with only one component. However, a decorator adds additional responsibilities—it isn’t intended for object aggregation.

 

Strategy: A decorator lets you change the skin of an object; a strategy lets you change the guts. These are two alternative ways of changing an object.

 

Non-Software Example

The Decorator attaches additional responsibilities to an object dynamically. Although paintings can be hung on a wall with or without frames, frames are often added, and it is the frame which is actually hung on the wall. Prior to hanging, the paintings may be matted and framed, with the painting, matting, and frame forming a single visual component.

 

Decorator Pattern Realworld Example

 

How useful was this post?

Click on a star to rate it!

We are sorry that this post was not useful for you!

Let us improve this post!

Tell us how we can improve this post?

Suryateja Pericherla

Suryateja Pericherla, at present is a Research Scholar (full-time Ph.D.) in the Dept. of Computer Science & Systems Engineering at Andhra University, Visakhapatnam. Previously worked as an Associate Professor in the Dept. of CSE at Vishnu Institute of Technology, India.

He has 11+ years of teaching experience and is an individual researcher whose research interests are Cloud Computing, Internet of Things, Computer Security, Network Security and Blockchain.

He is a member of professional societies like IEEE, ACM, CSI and ISCA. He published several research papers which are indexed by SCIE, WoS, Scopus, Springer and others.

Note: Do you have a question on this article or have a suggestion to make this article better? You can ask or suggest us by filling in the below form. After commenting, your comment will be held for moderation and will be published in 24-48 hrs.

Leave a Reply

Your email address will not be published. Required fields are marked *