Decorator Pattern of Java Design Patterns (Decorator Pattern)

1. What is a design pattern? A
design pattern refers to a solution that has been verified during the software development process to solve recurring and specific problems in a specific environment. It can be used to improve code reusability, maintainability, readability, robustness, and security. In 1995, GoF (Gang of Four, Gang of Four) co-published the book "Design Patterns: The Foundation of Reusable Object-Oriented Software", which included a total of 23 design patterns. Since then, it has established the best in the field of software design patterns. Milestone, known as the "GoF Design Mode."
Classification:
a. Creation mode: singleton mode, abstract factory mode, builder mode, factory mode, prototype mode.
b. Structural mode: adapter mode, bridge mode, decoration mode, combination mode, appearance mode, flyweight mode, proxy mode.
c. Behavioral mode: template method mode, command mode, iterator mode, observer mode, mediator mode, memo mode, interpreter mode (Interpreter mode), state mode, strategy mode, chain of responsibility mode (chain of responsibility mode) , Visitor mode.

2. Decorator Pattern (Decorator Pattern) The
decorator pattern dynamically attaches more responsibilities to an object in a way that is transparent to the user. In other words, the client does not feel any difference between the object before and after decoration.
The class diagram of
Insert picture description here
the decorator pattern is as follows: the roles in the decor pattern are:
• Component: abstract component, the parent class common to the decorator and the decorated, is an interface or abstract class used to define basic behavior
• ConcreteComponent: define concrete Object, that is, decorator
• Decorator: Abstract decorator, inherited from Component, and extends ConcreteComponent from outer class.
• ConcreteDecorator: concrete decorator, used to extend ConcreteComponent
abstract components

public interface Component {
    
    public void sampleOperation();
    
}

Decorated

public class ConcreteComponent implements Component {
    @Override
    public void sampleOperation() {
        // 写相关的业务代码
    }
}

Abstract decorator

public class Decorator implements Component{
    private Component component;
    
    public Decorator(Component component){
        this.component = component;
    }
    @Override
    public void sampleOperation() {
        // 委派给构件
        component.sampleOperation();
    }   
}

Specific decorator

public class ConcreteDecoratorA extends Decorator {
    public ConcreteDecoratorA(Component component) {
        super(component);
    }
    
    @Override
    public void sampleOperation() {
      // 写相关的业务代码
   super.sampleOperation();
     // 写相关的业务代码
    }
}

3. Demonstration of the decorator pattern.
We set up a mobile stall to sell hand cakes. Our hand cakes are rich in content. You can add eggs, ham, tomato sauce, etc., but if you add different ingredients, you need to add money. How to dynamically calculate this price? Using the decorator mode, our stall is an abstract component , the hand cake is the decorator , the egg ham sausage, etc. are the specific decorators, and the egg ham sausage, etc., we collectively call the ingredients as the abstract decorator .
First look at the class diagram of our example:
Insert picture description here
code implementation:
1. Abstract component-stall

/**
 * @Author: huangguopan
 * @Date: 2019/7/8 13:38
 * @Description: 抽象构件  流动摊子
 */
public interface Store {
    //商品描述
    String desc();
    //价格
    double cost();
}

2. The garnished-hand cake

/**
 * @Author: huangguopan
 * @Date: 2019/7/8 13:38
 * @Description: 具体构件  手抓饼
 */
public class Shouzhuabing {
    public String desc() {
        return "我是一个手抓饼,";
    }
    public double cost() {
        return 5;
    }
}

3. Abstract decorator – ingredients

/**
 * @Author: huangguopan
 * @Date: 2019/7/8 13:45
 * @Description:  抽象装饰角色  配料
 */
public class Peiliao extends Shouzhuabing {
    Shouzhuabing shouzhuabing;
    public Peiliao(Shouzhuabing shouzhuabing) {
        this.shouzhuabing = shouzhuabing;
    }
    @Override
    public String desc() {
        return shouzhuabing.desc();
    }
    @Override
    public double cost() {
        return shouzhuabing.cost();
    }
}

3. Specific decorator-eggs

/**
 * @Author: huangguopan
 * @Date: 2019/7/8 13:39
 * @Description:  具体装饰  鸡蛋
 */
public class Jidan extends Peiliao {
    public Jidan(Shouzhuabing shouzhuabing) {
        super(shouzhuabing);
    }
    @Override
    public String desc() {
        return shouzhuabing.desc()+"加鸡蛋";
    }
    @Override
    public double cost() {
        return shouzhuabing.cost()+1;
    }
}

4. Specific decorator-ham sausage

/**
 * @Author: huangguopan
 * @Date: 2019/7/8 13:39
 * @Description: 具体装饰  火腿肠
 */
public class Huotuichang extends Peiliao {
    public Huotuichang(Shouzhuabing shouzhuabing) {
        super(shouzhuabing);
    }
    String shouroujing() {
        return "我加了瘦肉精";
    }
    @Override
    public String desc() {
        return shouzhuabing.desc()+"加火腿肠";
    }
    @Override
    public double cost() {
        return shouzhuabing.cost()+1;
    }
}

5. Specific decorator – tomato sauce

/**
 * @Author: huangguopan
 * @Date: 2019/7/8 13:39
 * @Description: 具体装饰  番茄酱
 */
public class Fanqiejiang extends Peiliao {
    public Fanqiejiang(Shouzhuabing shouzhuabing) {
        super(shouzhuabing);
    }
    @Override
    public String desc() {
        return shouzhuabing.desc()+"加番茄酱";
    }
    @Override
    public double cost() {
        return shouzhuabing.cost()+1;
    }
}

6. Test category:

/**
 * @Author: huangguopan
 * @Date: 2019/7/8 13:51
 * @Description:
 */
public class TestDecorator {
    public static void main(String[] args) {
        Store store = new Shouzhuabing();
        //单层装饰-只加火腿肠
        Store huotuichang = new Huotuichang(store);
        System.out.println(huotuichang.desc());
        System.out.println(huotuichang.cost());
        //双层装饰--加鸡蛋和火腿肠
        Store jidanHuotui = new Jidan(new Huotuichang(store));
        System.out.println(jidanHuotui.desc());
        System.out.println(jidanHuotui.cost());
    }
}

result:
Insert picture description here

4. Simplification of the decorator pattern In
most cases, the implementation of the decorator pattern is simpler than the schematic example given above.
If there is only one ConcreteComponent class, then you can consider removing the abstract Component class (interface) and use Decorator as a ConcreteComponent subclass. As shown in the following figure: The
simplified version of the class diagram is as follows:
Insert picture description here
Use the simplified version of the example just now to illustrate : If my mobile stall only sells hand-picked cakes, it can be simplified if it does not sell other items such as pancakes and fried potatoes.
Insert picture description here

Dynamic requirements: For
example, the user complains that my hand cake ingredients are too few, I need to go to the supermarket to add some ingredients, such as pork floss, cucumber, etc., I don’t need to modify the hand cake or other ingredients code, just inherit the previous The ingredients are fine. In other words, to add a new decorator, I only need to inherit the abstract decorator. It is not intrusive to the previous class and satisfies the principle of opening and closing.
Transparency requirements: The transparency of the
decorator mode to the client requires that the program not declare a variable of type ConcreteComponent, but a variable of type Component.
Using the example just now, I should state that I am selling hand cakes rather than ingredients, not eggs or the like.
For example:

Shouzhuabing shouzhuabing = new Shouzhuabing();
        
Shouzhuabing huotuichang = new Huotuichang(shouzhuabing);

Instead of:

Huotuichang huotuichang = new Huotuichang(shouzhuabing);
Jidan jidan = new Jidan(shouzhuabing);

Translucent decorator pattern
However, pure decorator patterns are hard to find. The purpose of the decorator pattern is to enhance the performance of the class under consideration without changing the interface. When enhancing performance, it is often necessary to establish new public methods. As in the example just now, when the customer wants to add ingredients, specify the egg to be marinated or fried. This is a new method of adding eggs. The parent does not know it, so it needs to be transformed downward.

Shouzhuabing shouzhuabing = new Shouzhuabing();

//I'm a local tyrant with braised eggs

Shouzhuabing ludan = new Jidan(shouzhuabing);
System.out.println(((Jidan) ludan).addLudan());

5. Application of decorator pattern in Java IO stream
The most famous application of decorator pattern in Java language is the design of Java I/O standard library.
Since the Java I/O library requires various combinations of many properties, if these properties are achieved by inheritance, then each combination requires a class, which will cause a large number of classes with repeated properties to appear. And in the decorator mode, we can see this code:

new BufferedReader(new InputStreamReader(instream, encoding));)

It can be seen that we convert a byte stream into a character stream and add buffering to improve efficiency.
The class diagram of the Java I/O library is as follows. Because there are many objects of Java I/O, only the InputStream part is drawn:
Insert picture description here
According to the above figure, we can see:
● Abstract component (Component): Played by InputStream. This is an abstract class that provides a unified interface for various subtypes.
● Decorated (ConcreteComponent): Played by ByteArrayInputStream, FileInputStream, PipedInputStream, StringBufferInputStream and other classes. They implement the interface specified by the role of the abstract component.
● Abstract decorator (Decorator): played by FilterInputStream. It implements the interface specified by InputStream. The role is to encapsulate other input streams and provide them with additional functions, namely abstract decorators.
● Concrete decorator (ConcreteDecorator): played by several classes, namely BufferedInputStream, DataInputStream, and two rarely used classes LineNumberInputStream and PushbackInputStream. That is, the specific decorator.
For example, the function of BufferedInputStream is to "provide buffering functions for input streams, as well as mark() and reset() functions". You can see that those two new methods are only available to subclasses, and the parent class does not know it, that is, above us. The mentioned translucent.

6. Summarize
the advantages of decoration mode
(1) The purpose of decoration mode and inheritance relationship is to extend the function of the object, but decoration mode can provide more flexibility than inheritance. The decoration mode allows the system to dynamically decide to "paste" a needed "decoration" or remove an unnecessary "decoration".
(2) By using different specific decoration types and the permutation and combination of these decoration types, many combinations of different behaviors can be created.
Disadvantages of the
decoration pattern Using the decoration pattern will produce more objects than using inheritance. More objects will make troubleshooting difficult, especially if these objects look alike.
Reference:
https://www.jianshu.com/p/d7f20ae63186

Guess you like

Origin blog.csdn.net/u010857795/article/details/104697376