Life is too short to have a dog

First, start from browsing 4S stores

Last week, I went to Xiaopeng’s experience shop on a whim. As soon as I entered the shop, the salesman began to introduce me to a variety of cars with different configurations. I heard that I was dizzy and dizzy, so I quickly left.

When I walked out of the store, the cool air touched my face, and I felt my brain was clear. I could not help thinking about the configuration information of the car that the salesman had just told me. After thinking about it for a while, it suddenly occurred to me that this thing could be implemented using decorator mode.

Second, basic concepts

1. What is decorator mode

The decorator pattern is an object structure pattern that dynamically adds responsibility/function to objects in a way that does not require subclasses to be defined. It uses associations between objects instead of inheritance relationships between classes. Its structure is shown in the figure below:

You can see the following four roles in the class diagram above:

  • Component (abstract Component): the base class of the class to be decorated and the base class of the decorator, in which the business method to be implemented is declared;
  • ConcreteCompnent ConcreteCompnent: As a class that needs to be decorated, only the most basic business logic needs to be realized in concrete components;
  • Decorator (abstract Decorator)Abstract decorators maintain a reference to the object of the abstract component (subclasses specify which specific component to use through methods such as constructors), that is, by combining the decorator and the decorator to establish a more relaxed relationship than inheritance. At the same time, as a subclass of abstract component, abstract decorator adds additional responsibilities to concrete component, and its additional responsibilities are realized in the subclass of abstract decorator.
  • ConcreteDecorator (ConcreteDecorator): As a subclass of abstract decorators, concrete decorators implement additional responsibilities that need to be added to concrete components;

2. A small example

In order to better distinguish the difference between inheritance relationship and decorator mode, we will use inheritance mode and decorator mode to implement different configurations in Xiaopeng P7 and P5 respectively.

2.1 Xiaopeng Automobile series based on inheritance relationship

First of all, we realized the following original models of Xiaopeng P7 and P5 through inheritance, with additional automatic driving, peng wing door and customized sound system with different configurations.

Instead of showing the corresponding code, a class diagram is given to illustrate the corresponding implementation. From the class diagram above, we can see that eight subclasses have been implemented without considering the configuration of cross combination. If there is a case where the function requires cross combination, the case of subclass guarantee will occur. Will this problem be alleviated in decorator mode?

2.2 Xiaopeng Automobile series based on decorator mode

With the above concept, we can try to use decorator mode to achieve various types of cars, various configurations of The Car.

The implementation of each class in the above class diagram is as follows:

PengCar

package DecoratorPattern;

/** * Xiaopeng Automobile **@author brucebat
 * @version 1.0
 * @since Created at 2021/5/23 10:50 下午
 */
public abstract class PengCar {

    /** * Run */
    abstract void run(a);
}

Copy the code

PengFiveCar

package DecoratorPattern;

/** * Xiao Peng P5 **@author brucebat
 * @version 1.0
 * @since Created at 2021/5/23 10:51 下午
 */
public class PengFiveCar extends PengCar{


    @Override
    void run(a) {
        System.out.println("Xiao peng (P5"); }}Copy the code

PengSevenCar

package DecoratorPattern;

/** * Xiaopeng P7 **@author brucebat
 * @version 1.0
 * @since Created at 2021/5/23 10:50 下午
 */
public class PengSevenCar extends PengCar{

    @Override
    void run(a) {
        System.out.println("Xiao peng P7"); }}Copy the code

PengDecorator

package DecoratorPattern;

import lombok.Data;
import lombok.EqualsAndHashCode;

/ * * *@author brucebat
 * @version 1.0
 * @since Created at 2021/5/23 10:52 下午
 */
@EqualsAndHashCode(callSuper = true)
@Data
public abstract class PengDecorator extends PengCar{

    private PengCar pengCar;

    public PengDecorator(PengCar pengCar) {
        this.pengCar = pengCar;
    }

    @Override
    void run(a) {
      	// Invoke the capabilities of the car itselfpengCar.run(); }}Copy the code

AutoDriveDecorator

package DecoratorPattern;

/** * Auto-pilot decorator **@author brucebat
 * @version 1.0
 * @since Created at 2021/5/23 10:54 下午
 */
public class AutoDriveDecorator extends PengDecorator {

    public AutoDriveDecorator(PengCar pengCar) {
        super(pengCar);
    }

    @Override
    void run(a) {
        super.run();
        System.out.println("Add autopilot!"); }}Copy the code

PengDoorDecorator

package DecoratorPattern;

/** *@author brucebat
 * @version 1.0
 * @since Created at 2021/5/23 10:56 下午
 */
public class PengDoorDecorator extends PengDecorator{

    public PengDoorDecorator(PengCar pengCar) {
        super(pengCar);
    }

    @Override
    void run(a) {
        super.run();
        System.out.println("Add the peng-wing door!); }}Copy the code

PengSpeakerDecorator

package DecoratorPattern;

/** * Custom sound decorator **@author brucebat
 * @version 1.0
 * @since Created at 2021/5/23 10:57 下午
 */
public class PengSpeakerDecorator extends PengDecorator {

    public PengSpeakerDecorator(PengCar pengCar) {
        super(pengCar);
    }

    @Override
    void run(a) {
        super.run();
        System.out.println("Add custom sound!"); }}Copy the code

App

package DecoratorPattern;

/ * * *@author brucebat
 * @version 1.0
 * @since Created at 2021/5/23 10:59 下午
 */
public class App {

    public static void main(String[] args) {
        // Take Xiaopeng P5 as an example
        PengFiveCar pengFiveCar = new PengFiveCar();
        AutoDriveDecorator autoDriveDecorator = new AutoDriveDecorator(pengFiveCar);
        PengDoorDecorator pengDoorDecorator = new PengDoorDecorator(autoDriveDecorator);
        PengSpeakerDecorator pengSpeakerDecorator = newPengSpeakerDecorator(pengDoorDecorator); pengSpeakerDecorator.run(); }}Copy the code

The final result

Autopilot added to Xiaopeng P5! Add a peng wing door! Add custom sound!Copy the code

From the final example, it can be seen that the responsibilities of Xiaopang P5 and decorators are relatively independent. If you want to arrange and combine different responsibilities, you only need to use the corresponding decorators to add responsibilities to the decorators, without additional subclasses.

3. Analyze the pros and cons

3.1 The advantages of decorator mode

As one of the design patterns, decorator pattern can be said to be the extreme interpretation of the open closed principle, extremely flexible to achieve the expansion of object functions, without causing the explosion of the number of subclasses brought by inheritance. And in the above example, you can see that in the process of function expansion, an object can be decorated several times, more flexible to achieve the arrangement and combination of a variety of functions, so as to create more capable objects.

Of course, the most important point, which is the basis of the above capabilities, is that the components and decorators are related to each other by combination rather than inheritance, so that they can operate independently of each other.

3.2 Disadvantages of decoration mode

Although decorators provide a more flexible extension of object functionality than the successor pattern, this also brings another problem, which is that after many decorators, debugging or troubleshooting needs to be done step by step, and the overall troubleshooting process can become cumbersome.

The decorator pattern in Java IO

This excellent design pattern is also used in the JDK, such as the IO class.

I’ve just picked the FileInputStream and BufferedInputStream classes to give a quick look at how the DECORator pattern is used in the JDK. As you can see from the class diagram above, FileInputStream is the concrete building blocks we talked about above. And the BufferedInputStream is the concrete decorator. In IO, a specific component is used to indicate the format in which the data came from. For example, FileInputStream above indicates that the data was obtained from a File. For example, BufferedInpuStream uses the BufferedInpuStream method to process the input data, adding the buffering function.

In addition to the two classes mentioned above, there are other corresponding classes in the Java IO class library, interested students can read the source code to learn more.