[C++ Design Pattern] Detailed Decoration Pattern

Thursday morning, August 31, 2023

This is the hardest design pattern I've come across so far....

It is very difficult to understand and more flexible, it is uncomfortable to learn, and it is difficult to write.....

Thursday, August 31, 2023 at 19:48

Finally finished, spent a day learning about the decorator pattern and writing this blog post.

Although I basically wrote down all my gains today,

But I feel that the writing is still not good enough. There are many things that have not been expressed clearly.

Will update later when I have time...


Table of contents


overview

The meaning of the decorator pattern

The decorator pattern is a structural design pattern that allows adding new functionality to an existing object without changing its structure.

Benefits of using the decorator pattern

  • You can dynamically add responsibilities to objects and extend object functions.
  • Compared to inheritance, the decorator pattern uses object composition instead of inheritance to extend functionality. more flexible.
  • The decorator pattern supports the open-closed principle, extending an object without modifying its code.

Why do you need the decorator pattern

  1. Dynamically extending functionality: The decorator pattern allows adding new functionality to an object dynamically at runtime without modifying the code of the original object. This avoids the explosive growth of class inheritance hierarchies, and is also more flexible and extensible.
  2. Single Responsibility Principle: The decoration pattern disperses functions into multiple decoration classes, and each decoration class only focuses on specific functions, following the single responsibility principle, making the code clearer and more maintainable.
  3. Open-Closed Principle: The decoration mode supports the extension of existing code without modifying the existing code, which conforms to the Open-Closed Principle. This avoids introducing potential risks and errors by modifying existing code.

When to use the decorator pattern

  1. The need to add new functionality or responsibilities to an object without changing the structure of the existing object.
  2. Functionality needs to be added dynamically to objects, and these functions can be combined and arranged.
  3. There is a need to extend the functionality of a class, but using inheritance can result in a class hierarchy that is too large or not feasible.
  4. Functionality needs to be dynamically added to objects at runtime, rather than statically determined at compile time.

scene

Suppose I have a class Xxx, and I need to add addition and subtraction functions to it,

But since this class is already very complicated, and the inheritance level is already very deep,

I don't want to change the code inside, and I don't want to make another subclass, so how to add these two functions?

class Xxx:public Ppp{
public:
	void func1();
	void func2();
	void func3();
	void func4();
	void func5();
	void func6();
	void func7();
};

In this case, the decorator pattern can be used to add these two functions,

Because there is no need to change the internal code of the class, nor to make another subclass.

// 原始类
class Xxx :public Ppp{
public:
  void func1() { /* 原始功能1的实现 */ }
  void func2() { /* 原始功能2的实现 */ }
  // ... 其他原始功能的实现
  void func7() { /* 原始功能7的实现 */ }
};

// 装饰类 - 加法功能
class AddDecorator : public Xxx {
private:
  Xxx* component;

public:
  AddDecorator(Xxx* component) : component(component) {}

  void func1() override {
    component->func1();
    // 加法功能的实现
  }
};

// 装饰类 - 减法功能
class SubtractDecorator : public Xxx {
private:
  Xxx* component;

public:
  SubtractDecorator(Xxx* component) : component(component) {}

  void func2() override {
    component->func2();
    // 减法功能的实现
  }
};

int main() {
  Xxx* xxx = new Xxx();

  // 使用加法功能的装饰类
  Xxx* xxxWithAddition = new AddDecorator(xxx);
  xxxWithAddition->func1();

  // 使用减法功能的装饰类
  Xxx* xxxWithSubtraction = new SubtractDecorator(xxx);
  xxxWithSubtraction->func2();

  delete xxxWithSubtraction;
  delete xxxWithAddition;
  delete xxx;

  return 0;
}

Note that this is not a complete decoration pattern, but it helps to understand the role of the decoration pattern.

standard decorator pattern

Main features of the decorator pattern

  • There is an abstract component class that defines the interface of the object.
  • Concrete component classes implement abstract component classes.
  • There is a decoration class inheriting the abstract component class, which contains the object reference of the abstract component class.
  • The decoration class can call the parent class interface to realize the extended function.

Example of a standard decorator program

#include <iostream>

// 抽象构件类
class Component {
public:
  virtual void func() = 0;
};

// 具体构件类
class ConcreteComponent : public Component {
public:
  void func() override {
    std::cout << "具体构件的操作" << std::endl;
  }
};

// 装饰类
class Decorator : public Component {
protected:
  Component* component;

public:
  Decorator(Component* component) : component(component) {}

  void func() override {
    if (component != nullptr) {
      component->func();
    }
  }
};

// 具体装饰类A
class ConcreteDecoratorA : public Decorator {
public:
  ConcreteDecoratorA(Component* component) : Decorator(component) {}

  void addedBehavior() {
    std::cout << "具体装饰类的附加行为A" << std::endl;
  }

  void func() override {
    Decorator::func();
    addedBehavior();
  }
};

// 具体装饰类B
class ConcreteDecoratorB : public Decorator {
public:
  ConcreteDecoratorB(Component* component) : Decorator(component) {}

  void addedBehavior() {
    std::cout << "具体装饰类的附加行为B" << std::endl;
  }

  void func() override {
    Decorator::func();
    addedBehavior();
  }
};

int main() {
  Component* component = new ConcreteComponent();
  
  //用decoratedComponentA修饰component
  Component* decoratedComponentA = new ConcreteDecoratorA(component);
  //用decoratedComponentB修饰被decoratedComponentA修饰过的component
  Component* decoratedComponentB = new ConcreteDecoratorB(decoratedComponentA);
  
  decoratedComponentB->func();
  
  //要记得释放申请的堆内存
  delete decoratedComponentA;
  delete decoratedComponentB;
  delete component;

  return 0;
}

My thoughts on the standard decorator pattern

How is the decoration mode implemented to add new functions without changing the original code and structure of the class?
How does the decorator decorate the concrete construction class?

They have the same abstract parent class
What does that mean? They will all have pure virtual functions of the abstract component class

The decorator needs to introduce an abstract component class.
It can introduce an abstract component class, which means that after passing in a specific component class object, only the methods of the abstract component class can be called.
The decorator will rewrite the method of the parent class and call it in the rewritten method Concrete component class methods

Concrete decorators have their own unique members and methods.
Concrete decorators will load specific component classes into
concrete decorators. Concrete decorators will rewrite the methods of abstract decorators, and call parent class methods and their own unique methods in the overridden methods
. How, the specific decoration class must introduce the abstract component class and pass in the concrete component class object

The core of the decoration mode lies in rewriting?
Add additional methods when rewriting

The concrete component class needs to implement the pure virtual function of the abstract component class, otherwise it cannot be created

What is the role of decorators?
Introduce a specific component class
Call the method of the specific component class in the overriding method

What is the role of abstract component class?

What is the role of specific component classes?
Define the most basic functions

What is the role of the specific decorator?
Write extra functionality, then add extra functionality by overriding methods

Example programs written using the standard decorator pattern

#include<iostream>

class Product{
public:
	virtual void buy()=0;
};

class Computer:public Product{
public:
	void buy ()override{
		std::cout<<"买了一台电脑"<<std::endl;
	}
};

class Decorate:public Product{
private:
	Product *product;
public:
	Decorate(Product *product):product(product){};
	
	void buy() override{
		if(product!=nullptr){
			product->buy();
		}
	}
};

class Mouse:public Decorate{
public:
	Mouse(Product *product):Decorate(product){};
	
	void buy() override{
		Decorate::buy();
		std::cout<<"又买了鼠标"<<std::endl;
	}
};

class KeyBoard:public Decorate{
public:
	KeyBoard(Product *product):Decorate(product){};
	
	void buy() override{
		Decorate::buy();
		std::cout<<"又买了键盘"<<std::endl;
	}
};

int main(){
	Product *computer=new Computer();
	Mouse *mouse=new Mouse(computer);
	KeyBoard *keyBoard=new KeyBoard(mouse);
	keyBoard->buy();
}

Guess you like

Origin blog.csdn.net/m0_61629312/article/details/132600100