Structural Patterns  «Prev 

Decorator Pattern in Java

Description:
The Decorator Pattern in Java is a structural design pattern that allows behavior to be added to an individual object dynamically, without modifying its underlying code or affecting other objects of the same class. It follows the principle of composition over inheritance, enabling flexible extension of functionality by wrapping an object with one or more decorator classes that implement the same interface. This pattern is particularly useful when you need to add responsibilities to objects in a way that is transparent to the client code, adhering to the open-closed principle, open for extension but closed for modification.
At its core, the Decorator Pattern involves a base component interface or abstract class, a concrete component that provides the core functionality, and decorator classes that wrap the component to extend its behavior. Each decorator implements the component interface and contains a reference to a component object, which it delegates calls to while adding its own behavior before or after the delegation. For example, consider a Coffee interface with a SimpleCoffee class. Decorators like MilkDecorator or SugarDecorator can wrap SimpleCoffee, adding their own cost and description while still calling the original methods. This chaining allows multiple decorators to be stacked, combining their effects seamlessly.
In practice, the Decorator Pattern shines in scenarios requiring flexible, runtime customization, such as Java’s own java.io package, where classes like BufferedReader decorate Reader to add buffering. However, it can increase complexity due to the proliferation of small classes and requires careful design to ensure decorators remain lightweight and focused. Compared to inheritance, decorators avoid rigid class hierarchies, offering greater flexibility but at the cost of additional object creation. This makes the pattern ideal for systems where behaviors need to be mixed and matched dynamically, like UI component libraries or stream processing.
The Decorator is known as a "structural pattern", because it is used to form large object structures across many disparate objects. The definition of the Decorator pattern provided in the original Gang of Four book on Design Patterns states:
Allows for the dynamic wrapping of objects in order to modify their existing responsibilities and behaviours

You might consider subclassing to be the best way to approach this challenge. However, there will be cases where subclassing is not possible. This leads us to the Open/Closed Principle: classes should be open for extension, but closed for modification. This is a good principle to keep in mind, as it keeps your class stable, but leaves it open for extension if someone wants to add behaviour.
Here is the Decorator Pattern in Java

The following is an email interface, which contains a getContents method:
package com.java.structural.decorator;

public interface IEmail{
  public String getContents();
}

I then provide a concrete implementation for use:
package com.java.structural.decorator;

//concrete component
public class Email implements IEmail{
  private String content;
  public Email(String content){
    this.content = content;
  }
  @Override
  public String getContents() {
    return content;
  }
}

Create a decorator which will wrap the base email with additional functionality and model this as an abstract class, and maintain a reference to the base email.

package com.java.structural.decorator;

public abstract class EmailDecorator implements IEmail {
  IEmail originalEmail;
}

Assumption: Emails that leave the company's internal server need to have a disclaimer added to the end and we will add in a decorator to handle this scenario.
package com.java.structural.decorator;
//concrete decorator
public class ExternalEmailDecorator extends EmailDecorator{
  private String content; 
  public ExternalEmailDecorator(IEmail basicEmail){
    originalEmail = basicEmail;
  }
  @Override
  public String getContents() {
    content = addDisclaimer(originalEmail.getContents());
    return content;
  }
  private String addDisclaimer(String message){
	  //append company disclaimer to message
    return  message + "\n Company Disclaimer";
  } 
}

Create a secure, encrypted message by using another decorator:
package com.java.structural.decorator;

//concrete decorator
public class SecureEmailDecorator extends EmailDecorator{
  private String content; 
  public SecureEmailDecorator(IEmail basicEmail){
    originalEmail = basicEmail;
  }
  @Override
  public String getContents(){
  //secure original 
    content = encrypt(originalEmail.getContents());
    return content;
  }
  private String encrypt(String message) {
    String encryptedMessage=message;
    return  encryptedMessage;
  }
}

If our email sending client detects this message is going outside the company, we can invoke the ExternalEmailDecorator before sending:
package com.java.structural.decorator;

public class EmailSender {
  public void sendEmail(IEmail email) {
  /*read the email to-address, to see if it
  is going outside of the company*/
  ExternalEmailDecorator external = new ExternalEmailDecorator(email);
  external.getContents();
  }
}