Structural Design Pattern: Decorator Pattern

Design pattern column directory

Creational Design Patterns - Singleton Pattern/Factory Pattern/Abstract Factory
Behavioral Design Pattern: Template Design Pattern/Observer Design Pattern/Strategy Design Pattern
Structural Design Pattern: Decorator
Mode

Classification of Design Patterns

Design patterns can be divided into three types: creational design patterns, structural design patterns, and behavioral design patterns.

Creational design patterns: These patterns involve the creation mechanism of objects , including simple factory pattern, factory method pattern, abstract factory pattern, singleton pattern, builder pattern and prototype pattern.

Structural design patterns: These patterns involve the combination of classes and objects , including adapter pattern, bridge pattern, composition pattern, decorator pattern, appearance pattern, flyweight pattern and proxy pattern.

Behavioral design patterns: These patterns involve communication and interaction between objects , including chain of responsibility pattern, command pattern, interpreter pattern, iterator pattern, intermediary pattern, memo pattern, observer pattern , state pattern, strategy pattern , Template method pattern and visitor pattern.

This article is a summary of decorators and combination design patterns in structural design patterns. The definition of each design pattern is relatively obscure, you can directly look at the code to understand.

Design Principles of Design Patterns

Dependency inversion : high-level modules should not depend on low-level modules, both should depend on abstraction; abstraction should not depend on concrete implementation, concrete implementation should depend on abstraction; (just remember to rely on abstraction ) .
Open and closed : a class should be open to extension (combination and inheritance) and closed to modification;
interface-oriented : the variable type is not declared as a specific concrete class, but declared as an interface;
the client program does not need to know the specifics of the object Type, you only need to know the interface of the object;
reduce the dependencies of each part of the system, so as to realize the type design scheme of "high cohesion and loose coupling"; (remember to only expose the interface, only call the interface) .
Encapsulate the change point : separate the stable point from the change point, expand and modify the change point; separate the implementation levels of the stable point and the change point; single responsibility : a class should have only one reason for its change; (that is, there should not be too many change points ) . Liskov substitution : The subtype must be able to replace its parent type; it mainly occurs when the subclass overrides the implementation of the parent class, and the program that originally used the parent type may have errors; the method of the parent class is covered but the responsibility of the method of the parent class is not implemented; ( That is, the subclass can override the method of the parent class, but the necessary functions of the parent class must be guaranteed) . Interface isolation : Clients should not be forced to depend on methods they don't use;it is generally used to deal with a class with more interfaces, and these interfaces involve many responsibilities;clients should not rely on interfaces they don't need. A class's dependence on another class should be based on the smallest interface. Composition over inheritance






: Inheritance coupling degree is high, composition coupling degree is low;

decorator pattern

Dynamically add some additional responsibilities to objects. Decoration is more flexible than subclassing in terms of adding functionality.

Use an example of calculating the cost of a dish (including food and various seasonings) to illustrate this design pattern:

In restaurants, you need to calculate the cost of food, such as noodles and various seasonings:

#include <iostream>
#include <string>

using namespace std;

// 食品类
class Food {
    
    
protected:
	string des;
	double price;

public:
	virtual double cost() = 0;
	string getDes() {
    
    
		return des;
	}
	void setDes(string des) {
    
    
		this->des = des;
	}
	double getPrice() {
    
    
		return price;
	}
	void setPrice(double price) {
    
    
		this->price = price;
	}
};

// 面条类
class Noodles : public Food {
    
    
public:
	double cost() override {
    
    
		return getPrice();
	}
};

// 中式面条类
class ChineseNoodles : public Noodles {
    
    
public:
	ChineseNoodles() {
    
    
		setDes("中式面条");
		setPrice(25.00);
	}
};

// 装饰器类
class Decorator : public Food {
    
    
protected:
	Food* desFood;

public:
	Decorator(Food* desFood) {
    
    
		this->desFood = desFood;
	}
	double cost() override {
    
    
		cout << desFood->getDes() << "价格:" << desFood->getPrice() << "  配料如下:"
			<< getDes() << "  价格:" << getPrice() << "  总价" << (getPrice() + desFood->cost()) << endl;
		return getPrice() + desFood->cost();
	}
};

// 孜然类
class Cumin : public Decorator {
    
    
public:
	Cumin(Food* desFood) : Decorator(desFood) {
    
    
		setDes("孜然");
		setPrice(2.00);
	}
};
// 胡椒类
class Peper : public Decorator {
    
    
public:
	Peper(Food* desFood) : Decorator(desFood) {
    
    
		setDes("胡椒");
		setPrice(3.00);
	}
};

int main() {
    
    
	// 先定义一个被装饰者,返回对象要为最顶层的对象,这样被装饰者才能接受
	Food* noodles = new ChineseNoodles();
	// 定义一个装饰者对象
	Food* cumin = new Cumin(noodles);
	// 输出为:中式面条价格:25配料如下:孜然价格:2总价27
	cout << "-----------面条+孜然------------------------" << endl;
	cumin->cost();
	cout << "-----------面条+胡椒------------------------" << endl;
	Food* peper = new Peper(noodles);
	peper->cost();
	cout << "-----------面条+胡椒+孜然------------------------" << endl;
	peper = new Peper(cumin);
	cout << "面条+胡椒+孜然价格:" <<peper->cost();

	delete cumin;
	delete noodles;
	delete peper;

	return 0;
}

insert image description here

In the example of "noodles + pepper + cumin", the log printing is messy, because the cost printing of the decorator class is nested, so the log printing is messy.

insert image description here

structure:

  • Decorated abstract interface (Food): Provides basic function methods and decoration method interfaces.
  • Specific decorators (Noodles): Inherit abstract classes and implement method interfaces.
  • Decorator public class (Decorator): implements a unified decoration method.
  • Concrete decorator class: custom decorator properties.

Usage scenario: In the software development process, sometimes you want to use some existing components (defined objects) . These components may only perform some core functions. But its functionality can be extended dynamically without changing its architecture . So these can all be implemented using the decorator pattern.

Features:

The decorator design pattern is implemented in the form of composition + inheritance.

The decorating class and the decorated class can develop independently without being coupled with each other.

The decorator pattern is an alternative to inheritance. The decorator pattern can dynamically extend the functionality of an implementing class.

Guess you like

Origin blog.csdn.net/weixin_44477424/article/details/131905486