"Design Pattern" Decorator Pattern

1. What is the decorator pattern?

When the functions of a class need to be expanded, inheritance can generally be used. However, if there are many types of functions that need to be expanded, many subclasses will inevitably be generated, increasing the complexity of the system. When using inheritance to expand functions, we must be able to Anticipating these extended functions means that these functions need to be determined at compile time. So is there any better way to expand functionality? The answer is the decorator pattern.

The decorator pattern can dynamically add some additional responsibilities to the object to expand the function. Different decorators can be selected at runtime to achieve different behaviors. It is more flexible than using inheritance. By arranging and combining different decoration classes, you can create It can produce many different behaviors and get objects with more powerful functions; it complies with the "opening and closing principle", and the decorated class and the decorated class change independently. The user can add new decorative classes and decorated classes as needed, and then modify them when using them. Combination, the original code does not need to be changed.

However, the decorator pattern also has shortcomings. First, it will generate a lot of small objects, which increases the complexity of the system. Second, it is more difficult to troubleshoot. For objects decorated multiple times, finding errors during debugging may require step-by-step troubleshooting, which is more cumbersome. .

2. UML structure diagram

  • Component: Abstract component defines an object interface and can dynamically add responsibilities to this object.
  • ConcreteComponent: A concrete component defines a specific object and can also add some responsibilities to this object.
  • Decorator: abstract decorative class, inherited from Component, extending the functions of the Component class from external classes, but for Component, there is no need to know the existence of Decorator.
  • ConcreteDecorator: Concrete decoration class, which has the function of adding responsibilities to Component.

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

3. Code implementation

3.1. Code example one

//定义被装饰者
interface Human
{
    void wearClothes();
}
 
//定时装饰者
abstract class Decorator implements Human
{
    private Human human;
 
    public Decorator(Human human)
    {
        this.human = human;
    }
 
    @Override
    public void wearClothes()
    {
        human.wearClothes();
    }
}
 
//下面定义三种装饰,这是第一个,第二个第三个功能依次细化,即装饰者的功能越来越多
class Decorator_zero extends Decorator {
 
    public Decorator_zero(Human human) {
        super(human);
    }
 
    public void goHome() {
        System.out.println("进房子。。");
    }
 
    @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("去衣柜找找看。。");
    }
 
    @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("找到一件D&G。。");
    }
 
    @Override
    public void wearClothes() {
        super.wearClothes();
        findClothes();
    }
}
 
 
class Person implements Human {
 
    @Override
    public void wearClothes() {
        System.out.println("穿什么呢。。");
    }
}
 
//测试类
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 the demo:

(1) The Decorator abstract class holds the Human interface, and all methods are 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 method calling super(human). This reflects the principle that the abstract class depends on the implementation of the subclass, that is, abstraction depends on the implementation. Because the parameters of the constructor are all Human types, as long as the Human implementation class is passed in, it will show the structure of Decorator dt = new Decorator_second(new Decorator_first(new Decorator_zero(human))), so when calling dt.wearClothes(), and because in each specific decorator class, the super.wearClothes() method is first called, and the super has been passed by the constructor and points to a specific decorator class, then the final call is the method of the decoration class, and then calls its own decoration method, which shows a decorative and chain-like behavior similar to filtering.

(3) The specific decorated class can define the initial state or the initial decoration of itself, and subsequent decoration behaviors will be embellished and decorated step by step on this basis.

(4) The design principle of the decorator pattern is: open to extension and closed to modification. This sentence is reflected in that if you want to extend the behavior of the decorated class, you do not need to modify the decorator abstract class, you only need to inherit the decorator abstract class and implement Some additional decorations or behaviors can be used to package the decorated object. Therefore: extension is reflected in inheritance and modification is reflected in subclasses, rather than specific abstract classes. This fully embodies the principle of dependency inversion, which is the decorator pattern that I understand.

3.2. Code example 2

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

Hamburger 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 its own, equivalent to the Person above) 

public class ChickenBurger extends Humburger {  
      
    public ChickenBurger(){  
        name = "鸡腿堡";  
    }  
  
    @Override  
    public double getPrice() {  
        return 10;  
    }  
}  

The base class of ingredients (decorator, used to decorate burgers in multiple layers, adding some ingredients to each layer of decoration, equivalent to the Decorator above)

public abstract class Condiment extends Humburger {  
      
    public abstract String getName();  
}  

Lettuce (the first layer of decorators, equivalent to decorator_zero above)

public class Lettuce extends Condiment {  
      
    Humburger humburger;  
      
    public Lettuce(Humburger humburger){  
        this.humburger = humburger;  
    }  
  
    @Override  
    public String getName() {  
        return humburger.getName()+" 加生菜";  
    }  
  
    @Override  
    public double getPrice() {  
        return humburger.getPrice()+1.5;  
    }  
}  

pepper (second layer of decorators, 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()+" 加辣椒";  
    }  
  
    @Override  
    public double getPrice() {  
        return humburger.getPrice();  //辣椒是免费的哦  
    }  
}  

Test class:

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

Output:

Chicken Leg Burger Price: 10.0  
Chicken Leg Burger with Lettuce Price: 11.5  
Chicken Leg Burger with Chili Price: 10.0  
Chicken Leg Burger with Lettuce and Chili Price: 11.5  

Original link:  Structural type of Java design pattern: Decorator pattern_Zhang Weipeng's blog-CSDN blog 

Guess you like

Origin blog.csdn.net/m0_50370837/article/details/126254405