Design Patterns - Structural Patterns - Decorator Patterns

Introduction to Decorator Pattern

The original definition of the decorator pattern is to dynamically add some additional responsibilities to an object. In terms of extending functionality, the decorator pattern provides a more flexible alternative to using subclasses.

Suppose there is a piece of cake now, if it is only coated with cream, then this cake is a normal cream cake , and if we add some blueberries, then this cake is a blueberry cake . If we take another piece of dark chocolate and write the name, insert Candles on behalf of the age, this is turned into a birthday cake

 

In software design, the decorator pattern is a technology used to replace inheritance. It dynamically adds responsibilities to objects in a way that does not need to define subclasses, and uses the association relationship between objects to replace the inheritance relationship between classes.

Decorator pattern principle

Roles in Decorator mode:

  • Abstract construction (Component) role: it is the common parent class of the concrete construction and the abstract decoration class, and declares the business method implemented in the concrete construction. It introduces the client to handle undecorated objects and decorations in a consistent manner After the object, realize the transparent operation of the client

  • Concrete Component (Concrete Component) role: It is a subclass of the abstract construction class, which is used to define specific construction objects and implement the methods declared in the abstract construction. The decoration class can add additional responsibilities (methods) to it.

  • Abstract decoration (Decorator) role: it is also a subclass of the abstract construction class, which is used to add responsibilities to the specific construction, but the specific responsibilities are implemented in its subclasses. It maintains a reference to the abstract construction object, through which it can call Decorate the method of constructing the object before, and extend the method through its subclasses to achieve the purpose of decoration.

  • Concrete Decorator (ConcreteDecorator) role: It is a subclass of the abstract decorator class, responsible for adding new responsibilities to the construction. Each concrete decorator class defines some new behaviors, it can call the methods defined in the abstract decorator class, and New methods can be added to extend the behavior of the object.

code show as below:

/**
 * 抽象构建类
 * 
 
 **/
public abstract class Component {

    //抽象方法
    public abstract void operation();
}

/**
 * 具体构建类
 * 
 
 **/
public class ConcreteComponent extends Component {

    @Override
    public void operation() {
        //基础功能实现(复杂功能通过装饰类进行扩展)
    }
}

 

/**
 * 抽象装饰类-装饰者模式的核心
 **/
public class Decorator extends Component{

    //维持一个对抽象构建对象的引用
    private Component component;

    //注入一个抽象构建类型的对象
    public Decorator(Component component) {
        this.component = component;
    }


    @Override
    public void operation() {
        //调用原有业务方法(这里并没有真正实施装饰,而是提供了一个统一的接口,将装饰过程交给子类完成)
        component.operation();
    }
}


/**
 * 具体装饰类
 **/
public class ConcreteDecorator extends Decorator {


    public ConcreteDecorator(Component component) {
        super(component);
    }

    @Override
    public void operation() {
        super.operation(); //调用原有业务方法
        addedBehavior(); //调用新增业务方法
    }

    //新增业务方法
    public void addedBehavior(){
        //......
    }
}

Application example of decorator pattern

Let's take a file reader program as an example to demonstrate the use of the decorator mode. The following is the UML class diagram of the program

 

  • DataLoader

    • Abstract file reading interface DataLoader

  • BaseFileDataLoader

    • The specific component BaseFileDataLoader, rewrite the read and write method of the component DataLoader

  • DataLoaderDecorator

    • The decorator DataLoaderDecorator, here should contain an object instance wrapper that refers to DataLoader, which also rewrites the DataLoader method, but here uses wrapper to read and write, and does not expand

  • EncryptionDataDecorator

    • The specific decorator EncryptionDataDecorator with encryption and decryption functions when reading and writing, it inherits the decorator DataLoaderDecorator to rewrite the reading and writing method

 Import the IO tool class

<dependencies>
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.6</version>
        </dependency>
    </dependencies>

1 ) DataLoader

/**
 * 抽象的文件读取接口DataLoader
 **/
public interface DataLoader {

    String read();

    void write(String data);
}

2 ) BaseFileDataLoader

/**
 * 具体组件,重写读写方法
 **/
public class BaseFileDataLoader implements DataLoader {

    private String filePath;

    public BaseFileDataLoader(String filePath) {
        this.filePath = filePath;
    }

    @Override
    public String read() {

        try {
            String result = FileUtils.readFileToString(new File(filePath), "utf-8");
            return result;
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }

    @Override
    public void write(String data) {
        try{
            FileUtils.writeStringToFile(new File(filePath), data, "utf-8");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

3 ) DataLoaderDecorator

/**
 * 抽象装饰者类
 **/
public class DataLoaderDecorator implements DataLoader {

    private DataLoader wrapper;

    public DataLoaderDecorator(DataLoader wrapper) {
        this.wrapper = wrapper;
    }

    @Override
    public String read() {
        return wrapper.read();
    }

    @Override
    public void write(String data) {
        wrapper.write(data);
    }
}

 4 ) EncryptionDataDecorator

 

/**
 * 具体装饰者-对文件内容进行加密和解密 
 **/
public class EncryptionDataDecorator extends DataLoaderDecorator {

    public EncryptionDataDecorator(DataLoader wrapper) {
        super(wrapper);
    }

    @Override
    public String read() {
        return decode(super.read());
    }

    @Override
    public void write(String data) {
        super.write(encode(data));
    }

    //加密操作
    private String encode(String data) {
        try {
             Base64.Encoder encoder = Base64.getEncoder();
             byte[] bytes = data.getBytes("UTF-8");
             String result = encoder.encodeToString(bytes);
             return result;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    //解密
    private String decode(String data) {
        try {
            Base64.Decoder decoder = Base64.getDecoder();
            String result = new String(decoder.decode(data), "UTF-8");
            return result;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
}

5) Test

public class TestDecorator {

    public static void main(String[] args) {

        String info = "name:tom,age:15";
        DataLoaderDecorator decorator = new EncryptionDataDecorator(new BaseFileDataLoader("demo.txt"));
        decorator.write(info);

        String data = decorator.read();
        System.out.println(data);
    }
}

Decorator pattern summary

Advantages of the decorator pattern:

  1. For extending the function of an object, the decoration mode is more flexible than inheritance, and will not cause a sharp increase in the number of classes

  2. The function of an object can be extended in a dynamic way, and different specific decoration classes can be selected at runtime through configuration files to achieve different behaviors.

  3. An object can be decorated multiple times. By using different specific decoration classes and the arrangement and combination of these decoration classes, many combinations of different behaviors can be created to obtain more powerful objects.

  4. The specific construction class and specific decoration class can be changed independently. Users can add new specific construction classes and specific decoration classes according to their needs. The code of the original class library is changed in disorder, which conforms to the principle of opening and closing.

Disadvantages of decorator pattern:

  1. When using the decoration mode for system design, many small objects will be generated. The difference between these objects lies in the way they are connected to each other, not their different classes or attribute values. The generation of a large number of small objects will inevitably occupy more space. More system resources will affect the performance of the program to a certain extent.

  2. The decorator mode provides a more flexible and flexible solution than inheritance, but it also means that it is more error-prone and more difficult to debug than inheritance. For objects decorated multiple times, it may be necessary to debug and find errors step by step Checking is more cumbersome.

Applicable scenarios of the decorator pattern

  1. Quickly and dynamically extend and revoke the functional scenarios of a class. For example, in some scenarios where the security requirements of the API interface are high, the decoration mode can be used to compress or encrypt the transmitted string data. If the security requirements are not high, you can not use it.

  2. The scenario of inheriting extended classes is not supported. For example, a class using the final keyword, or a large number of subclasses generated through inheritance in the system.

Guess you like

Origin blog.csdn.net/weixin_42151235/article/details/129923213