C++ Implementation of Decoration Mode - Design Pattern Learning (1)

Programming Purpose: To understand the decorator pattern and its usage.

Decorator, which dynamically adds some additional responsibilities to an object, is more flexible than generating subclasses in terms of adding functionality. [DP]

The decorator pattern is a structural design pattern that allows adding new behavior to objects dynamically at runtime. This pattern is implemented by creating a wrapper that contains the original object and adds new behavior at runtime. In this process, there is no need to modify the code of the original object, so the decoration mode is a very flexible mode.

Here is the C++ implementation of the decorator pattern:

First, we need to define a basic component class, which represents the object we want to add new behavior to. In this example, we take a simple string class as an example:

class Component {
public:
    virtual ~Component() {}
    virtual std::string operation() const = 0;
};

Next, we need to implement the concrete component class. In this example, we take a simple string class as an example:

class ConcreteComponent : public Component {
public:
    std::string operation() const override {
        return "ConcreteComponent";
    }
};

Then, we need to define a decorator class that wraps the concrete component and adds new behavior:

class Decorator : public Component {
public:
    Decorator(Component* component) : component_(component) {}
    std::string operation() const override {
        return component_->operation();
    }
protected:
    Component* component_;
};

Finally, we can implement concrete decorator classes to add new behavior:

class ConcreteDecoratorA : public Decorator {
public:
    ConcreteDecoratorA(Component* component) : Decorator(component) {}
    std::string operation() const override {
        return "ConcreteDecoratorA(" + Decorator::operation() + ")";
    }
};

class ConcreteDecoratorB : public Decorator {
public:
    ConcreteDecoratorB(Component* component) : Decorator(component) {}
    std::string operation() const override {
        return "ConcreteDecoratorB(" + Decorator::operation() + ")";
    }
};

In this example, we define two concrete decorator classes, ConcreteDecoratorA and ConcreteDecoratorB. These decorator classes are all inherited from the Decorator class, and their constructors all accept a pointer to the component object and store it in the class member variable. In these concrete decorator classes, we override action methods in order to add new behavior.

Now, we can use these classes to create an object with multiple behaviors:

Component* component = new ConcreteComponent();
Component* decoratorA = new ConcreteDecoratorA(component);
Component* decoratorB = new ConcreteDecoratorB(decoratorA);
std::cout << decoratorB->operation() << std::endl;

In this example, we first create a concrete component object. We then decorate it with ConcreteDecoratorA and store the result in the decoratorA variable. Next, we decorate decoratorA with ConcreteDecoratorB and store the result in the decoratorB variable. Finally, we output the result of decoratorB's operation, which will contain all added lines

for.

For this example, if we output the result of decoratorB's operation, it will be the following:

ConcreteDecoratorB(ConcreteDecoratorA(ConcreteComponent))

This is because we first decorate the ConcreteComponent as ConcreteDecoratorA, and then decorate the result as ConcreteDecoratorB, so the final result contains all the added behavior.

It should be noted that when using the decoration mode, we should avoid creating too many decorator objects, otherwise the code may become difficult to maintain. In addition, we should also carefully design the inheritance structure of decorator classes to ensure that the relationship between them is clear and unambiguous.

Guess you like

Origin blog.csdn.net/Fan0920/article/details/105774468