Structural Types of Java Design Patterns Decorator Patterns

1. What is the [decorator] pattern:

When the function of a class needs to be expanded, inheritance can generally be used, but if there are many types of functions to be expanded, many subclasses will be generated, which will increase the complexity of the system, and when using inheritance to achieve function expansion, we must be able to These extended functions are foreseen, that is, these functions need to be determined at compile time. So is there a better way to achieve functional expansion? The answer is the decorator pattern.

The decorator pattern can dynamically add some additional responsibilities to the object to achieve functional expansion, and choose different decorators at runtime to achieve different behaviors; it is more flexible than using inheritance. By arranging and combining different decoration classes, creating Many different behaviors can be obtained to obtain objects with more powerful functions; in line with the “open and closed principle”, the decorated class and the decorated class can be changed independently. combination, the original code does not need to be changed.

However, the decorator mode also has shortcomings. First, many small objects will be generated, which increases the complexity of the system. Second, it is difficult to troubleshoot. For objects decorated multiple times, it may be necessary to check for errors step by step during debugging, which is more cumbersome. .

Second, UML structure diagram:

  • Component: An abstract component that defines an object interface that can dynamically add responsibilities to this object.
  • ConcreteComponent: A specific component defines a specific object, and can also add some responsibilities to this object.
  • Decorator: Abstract decorator class, inherited from Component, extends the function of Component class from outer class, but for Component, there is no need to know the existence of Decorator.
  • ConcreteDecorator: A concrete decoration class that adds responsibilities to Component.

*Both the decorator and the decorated have a common superclass, but the purpose of inheritance here is to inherit the type, not the behavior.*

3. Code implementation:

1. Code example 1:

//Define the decorated 
interface  Human
 {
     void  wearClothes () ;
}

//Timing decorator 
abstract  class  Decorator  implements  Human
 {
     private Human human;

    public Decorator(Human human)
    {
        this.human = human;
    }

    @Override
    public void wearClothes()
    {
        human.wearClothes();
    }
}

//Three kinds of decoration are defined below, this is the first, the second and third functions are refined in turn, that is, the functions of the decorator are more and more 
class  Decorator_zero  extends  Decorator  {

    public Decorator_zero(Human human) {
        super(human);
    }

    public void goHome() {
        System.out.println( "Into the house.." );
    }

    @Override
    public void wearClothes() {
        super.wearClothes();
        goHome();
    }
}

class Decorator_first extends Decorator {

    public Decorator_first(Human human) {
        super(human);
    }

    public void goClothespress() {
        System.out.println( "Go to the closet and look for it.." );
    }

    @Override
    public void wearClothes() {
        super.wearClothes();
        goClothespress();
    }
}

class Decorator_two extends Decorator {

    public Decorator_two(Human human) {
        super(human);
    }

    public void findClothes() {
        System.out.println( "Found a D&G.." );
    }

    @Override
    public void wearClothes() {
        super.wearClothes();
        findClothes();
    }
}


class Person implements Human {

    @Override
    public void wearClothes() {
        System.out.println( "What to wear..." );
    }
}

//Test class 
public  class  DecoratorTest
 {
     public  static  void  main (String[] args)
     {
        Human person = new Person();
        Decorator decorator = new Decorator_two(new Decorator_first(new Decorator_zero(person)));
        decorator.wearClothes();
    }
}

operation result:

In fact, it is to go into the house to find clothes, and enrich the details through the three-layer decoration of the decorator. The key points of this demo:

(1) The Decorator abstract class holds the Human interface, and the methods are all delegated to the interface for invocation, the purpose is to hand it over to the implementation class of the interface for invocation.

(2) The subclass of the Decorator abstract class, that is, the concrete decorator, has a constructor calling super(human), which reflects the principle that the abstract class depends on the subclass implementation, that is, the abstraction depends on the implementation. Because the parameters of the constructor are all of Human type, as long as the implementation class of the Human can be passed in, it shows the structure of Decorator dt = new Decorator_second(new Decorator_first(new Decorator_zero(human))), so when calling When dt.wearClothes(), because each specific decorator class calls the super.wearClothes() method first, and the super has been passed by the constructor and points to a specific decorator class, then the final call It is the method of decorating the class, and then calling its own decorating method, that is, showing a decorative, chain-like behavior similar to filtering.

(3) The specific decorate class can define the initial state or the initial own decoration, and the subsequent decoration behaviors are decorated and decorated step by step on this basis.

(4) The design principle of the decorator pattern is: open for extension and closed for modification. This sentence is reflected in the fact that if you want to extend the behavior of the decorated class, you do not need to modify the abstract decorator class, but only need to inherit the abstract decorator class to achieve Some additional decorations or behaviors can wrap the decorated object. So: extension is reflected in inheritance, modification is reflected in subclasses, not concrete abstract classes, which fully reflects the principle of dependency inversion, which is the decorator pattern that I understand.

2. Code example 2:

Now you need a burger, the main body is a chicken burger, you can choose to add lettuce, sauce, peppers and many other ingredients, in this case you can use the decorator mode.

Burger base class (decorated, equivalent to Human above)

public abstract class Humburger {  

    protected  String name ;  

    public String getName(){  
        return name;  
    }  
    public abstract double getPrice();  
}

Chicken drumstick class (the initial state of the decorated person, some simple decorations of their own, equivalent to the Person above)

public class ChickenBurger extends Humburger {  

    public ChickenBurger(){  
        name = "Drumstick Burger" ;  
    }  

    @Override  
    public double getPrice() {  
        return 10;  
    }  
}

The base class of ingredients (decorator, used to decorate the burger with multiple layers, each layer of decoration adds some ingredients, which is equivalent to the above Decorator)

public abstract class Condiment extends Humburger {  

    public abstract String getName();  
}

Lettuce (first layer of decorator, equivalent to decorator_zero above)

public class Lettuce extends Condiment {  

    Humburger humburger;  

    public Lettuce(Humburger humburger){  
        this.humburger = humburger;  
    }  

    @Override  
    public String getName() {  
    }  

    @Override  
    public double getPrice() {  
        return humburger.getPrice()+1.5;  
    }  
}

Chili (second layer of decorator, equivalent to decorator_first above)

public class Chilli extends Condiment {  

    Humburger humburger;  

    public Chilli(Humburger humburger){  
        this.humburger = humburger;  

    }  

    @Override   
    public String getName ()  {  
         return humburger.getName()+ "Add Chili" ;  
    }  

    @Override   
    public  double  getPrice ()  {  
         return humburger.getPrice();   // Chili is free  
    }  
}

Test class:

package decorator;  

public class Test {  
    public static void main(String[] args) {  
        Humburger humburger = new ChickenBurger();  
        Lettuce lettuce = new Lettuce(humburger);  
        Chilli chilli = new Chilli(humburger);  
        System.out .println ( chilli.getName ()+ "Price:" +chilli.getPrice());  
        Chilli chilli2 = new Chilli(lettuce);  
        System.out .println ( chilli2.getName ()+ "Price:" +chilli2.getPrice());  
    }  
}

output:

Chicken Thigh Burger Price: 10.0   
Chicken Thigh Burger with Lettuce Price: 11.5   
Chicken Thigh Burger with Chili Price: 10.0   
Chicken Thigh Burger with Lettuce and Chilli Price: 11.5

[Design Patterns] series of articles:

Creation of Java Design Patterns: Detailed Explanation of Factory Patterns (Simple Factory + Factory Method + Abstract Factory)

The creation of Java design patterns: the builder pattern

The creation of Java design patterns: the singleton pattern

The creation type of Java design pattern: prototype pattern

Structural Types of Java Design Patterns: Adapter Patterns

Structural Types of Java Design Patterns: Decorator Patterns

The Structural Type of Java Design Patterns: The Proxy Pattern

Structural Types of Java Design Patterns: Bridge Patterns

Structural Types of Java Design Patterns: Facade Patterns

Structural Types of Java Design Patterns: Composition Patterns

Structural Types of Java Design Patterns: Flyweight Pattern

Behavioral Types of Java Design Patterns: Strategy Patterns

Behavioral Types of Java Design Patterns: Template Method Pattern

Behavioral Types of Java Design Patterns: The Chain of Responsibility Pattern

Behavioural of Java Design Patterns: Observer Pattern

Behavioral Types of Java Design Patterns: The Visitor Pattern

Behavioral Types of Java Design Patterns: The Mediator Pattern

Behavioral Types of Java Design Patterns: Command Patterns

Behavioral Types of Java Design Patterns: State Patterns

Behavioral Types of Java Design Patterns: The Memento Pattern

Behavioral Types of Java Design Patterns: The Iterator Pattern

Behavioral Types of Java Design Patterns: Interpreter Patterns

Original blog link:

[JAVA Design Patterns Preliminary Exploration of Decorator Patterns]

Design pattern reading notes —– decorator pattern – chenssy’s technical blog – CSDN blog

Leave a Comment

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