What is decorator pattern?

Decorator pattern is a structural pattern. The purpose is to extend the function of the object, by holding the reference of the object, the object is wrapped up, you can add new functions before or after calling the method of the object, in order to add some additional functions to the object, this operation is called decoration. Decorators can be multiple, and once an object has been wrapped, it can be wrapped again to add new functionality, in order to extend the object’s functionality. It makes the system very resilient, following the object-oriented principles: open for extension, closed for modification. If new requirements change and object functionality is extended, simply add a decorator class and wrap the object to extend the functionality of the object without modifying the old original object code.

Method rewriting by inheritance and subclasses can also extend the functions of objects, but the flexibility is poor. Once the business changes or new business functions are added, the code of the implementation class needs to be opened for modification, so as to check the old code and ensure the correctness of the new code. Class inheritance relationships are determined at compile time and cannot be changed dynamically at run time. Using decorator patterns, objects can be added dynamically at run time and extended indefinitely. The decorator pattern is a better alternative to inheritance to extend object functionality.

What’s an example?

1) Create an interface

public interface Shape {
    
    void draw();
}
Copy the code

2) Create an entity class that implements the interface

public class Rectangle implements Shape { @Override public void draw() { System.out.println("Shape: Rectangle"); }}Copy the code
public class Circle implements Shape { @Override public void draw() { System.out.println("Shape: Circle"); }}Copy the code

Create an abstract decorator class that implements the Shape interface

public abstract class ShapeDecorator implements Shape { protected Shape decoratedShape; public ShapeDecorator(Shape decoratedShape){ this.decoratedShape = decoratedShape; } @Override public void draw(){ decoratedShape.draw(); }}Copy the code

4) Create an entity decorator class that extends the ShapeDecorator class

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"); }}Copy the code

5) Use a RedShapeDecorator to decorate the Shape object

public static void main(String[] args) {
    Shape circle = new Circle();
    ShapeDecorator redCircle = new RedShapeDecorator(new Circle());
    ShapeDecorator 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();
}
Copy the code

6) Console output results

conclusion

The decorator pattern involves four roles: Component: An abstract interface to Component objects that can dynamically add responsibilities/functions to them. In the example above, the Shape interface; ConcreteComponent: specific components of the object, the interface of component objects, is a decorator decoration of the original object, it can not only add to this object dynamic responsibility, in the example above Circle and Rectangle; Decorator: An abstract parent of all decorators that implements the interface to the component object and holds a component object (the object being decorated), like the ShapeDecorator in the above example; ConcreteDecorator: ConcreteDecorator that implements adding functionality to a decorator object, like the RedShapeDecorator in the above example. Note that decorator mode only enhances functionality, does not change interfaces, and is essentially dynamic composition.