Decorator pattern


The Decorator Pattern allows adding new functionality to an existing object without changing its structure. This type of design pattern is a structural pattern, which acts as a wrapper around an existing class.

This mode creates a decoration class to wrap the original class and provide additional functionality while maintaining the integrity of the class method signature.

We demonstrate the usage of the decorator pattern through the following example. Among them, we will decorate a shape with different colors without changing the shape class.

Introduction

Intent: Dynamicly add some additional responsibilities to an object. In terms of adding functionality, the decorator pattern is more flexible than generating subclasses.

Main solution:Generally, we often use inheritance to extend a class. Since inheritance introduces static features to the class, and as the extension functions increase, the subclass will expand. .

When to use: Extend a class without adding many subclasses.

How to solve: Divide specific functional responsibilities and inherit the decorator pattern.

Key code: 1. The Component class plays an abstract role and should not be implemented concretely. 2. Modify the class to reference and inherit the Component class, and specifically extend the class to override the parent class method.

Application examples: 1. Sun Wukong has 72 changes. When he becomes a "temple", he is still basically a monkey, but he has the function of a temple. 2. A painting can be hung on the wall whether it has a frame or not, but it usually has a frame, and the frame is actually hung on the wall. Before being hung on the wall, the painting can be glazed and framed; then the painting, glass and frame form one object.

Advantages: The decorating class and the decorated class can develop independently and will not be coupled to each other. The decoration mode is an alternative mode to inheritance. The decoration mode can dynamically extend the functions of an implementation class.

Disadvantages: Multi-layer decoration is more complicated.

Usage scenarios: 1. Extend the functionality of a class. 2. Dynamically add functions and dynamically cancel them.

Note: can replace inheritance.

Implementation

We will create a Shape interface and an entity class that implements the Shape interface. Then we create an abstract decoration class ShapeDecorator that implements the Shape interface, and use the Shape object as its instance variable.

RedShapeDecorator is an entity class that implements ShapeDecorator.

DecoratorPatternDemo, our demo class uses RedShapeDecorator to decorate Shape objects.

decorator_pattern_uml_diagram.jpg

Step 1

Create an interface.

Shape.java

public interface Shape {
   void draw();
}

Step 2

Create an entity class that implements the interface.

Rectangle.java

public class Rectangle implements Shape {

   @Override
   public void draw() {
      System.out.println("Shape: Rectangle");
   }
}

Circle.java

public class Circle implements Shape {

   @Override
   public void draw() {
      System.out.println("Shape: Circle");
   }
}

Step 3

Create an abstract decoration class that implements the Shape interface.

ShapeDecorator.java

public abstract class ShapeDecorator implements Shape {
   protected Shape decoratedShape;

   public ShapeDecorator(Shape decoratedShape){
      this.decoratedShape = decoratedShape;
   }

   public void draw(){
      decoratedShape.draw();
   }	
}

Step 4

Create an entity decoration class that extends the ShapeDecorator class.

RedShapeDecorator.java

public class RedShapeDecorator extends ShapeDecorator {

   public RedShapeDecorator(Shape decoratedShape) {
      super(decoratedShape);		
   }

   @Override
   public void draw() {
      decoratedShape.draw();	       
      setRedBorder(decoratedShape);
   }

   private void setRedBorder(Shape decoratedShape){
      System.out.println("Border Color: Red");
   }
}

Step 5

Use RedShapeDecorator to decorate the Shape object.

DecoratorPatternDemo.java

public class DecoratorPatternDemo {
   public static void main(String[] args) {

      Shape circle = new Circle();

      Shape redCircle = new RedShapeDecorator(new Circle());

      Shape redRectangle = new RedShapeDecorator(new Rectangle());
      System.out.println("Circle with normal border");
      circle.draw();

      System.out.println("\nCircle of red border");
      redCircle.draw();

      System.out.println("\nRectangle of red border");
      redRectangle.draw();
   }
}

Step 6

Verify the output.

Circle with normal border
Shape: Circle

Circle of red border
Shape: Circle
Border Color: Red

Rectangle of red border
Shape: Rectangle
Border Color: Red