结构型设计模式:装饰器模式

设计模式专栏目录

创建型设计模式-单例模式/工厂模式/抽象工厂
行为型设计模式:模板设计模式/观察者设计模式/策略设计模式
结构型设计模式:装饰器模式
C#反射机制实现开闭原则的简单工厂模式

设计模式分类

设计模式可以分为三种类型:创建型设计模式、结构型设计模式和行为型设计模式。

创建型设计模式:这些模式涉及到对象的创建机制,包括简单工厂模式、工厂方法模式、抽象工厂模式、单例模式、建造者模式和原型模式。

结构型设计模式:这些模式涉及到类和对象的组合,包括适配器模式、桥接模式、组合模式、装饰器模式、外观模式、享元模式和代理模式。

行为型设计模式:这些模式涉及到对象之间的通信和交互,包括责任链模式、命令模式、解释器模式、迭代器模式、中介者模式、备忘录模式、观察者模式、状态模式、策略模式模板方法模式和访问者模式。

本文是对结构型设计模式中的装饰器、组合设计模式的一个总结。每个设计模式的定义都比较晦涩,可以直接看代码理解。

设计模式的设计原则

依赖倒置:高层模块不应该依赖低层模块,两者都应该依赖抽象; 抽象不应该依赖具体实现,具体实现应该依赖于抽象; (记住依赖抽象就好了)
开放封闭:一个类应该对扩展(组合和继承)开放,对修改关闭;
面向接口:不将变量类型声明为某个特定的具体类,而是声明为某个接口;
客户程序无需获知对象的具体类型,只需要知道对象所具有的接口;
减少系统中各部分的依赖关系,从而实现“高内聚、松耦合”的类型设计方案;(记住只暴露接口,只调用接口)
封装变化点:将稳定点和变化点分离,扩展修改变化点;让稳定点和变化点的实现层次分离;
单一职责:一个类应该仅有一个引起它变化的原因; (就是变化点不要太多)
里氏替换:子类型必须能够替换掉它的父类型;主要出现在子类覆盖父类实现,原来使用父类型的程序可能出现错误;覆盖了父类方法却没有实现父类方法的职责;( 就是子类可以覆盖父类的方法,但是得保证父类必要的功能)
接口隔离:不应该强迫客户依赖于它们不用的方法;
一般用于处理一个类拥有比较多的接口,而这些接口涉及到很多职责;
客户端不应该依赖它不需要的接口。
一个类对另一个类的依赖应该建立在最小的接口上。
组合优于继承:继承耦合度高,组合耦合度低;

装饰器模式

动态的给对象添加一些额外的责任,就增加功能来说,装饰比生成子类更为灵活。

用一个菜品计算成本(包括食物和各种调料)的例子说明这个设计模式:

在餐馆需要给食物计算成本,比如面条和加的各种调料:

#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;
}

在这里插入图片描述

“面条+胡椒+孜然”的例子日志打印比较乱,是由于装饰器类cost打印有嵌套,所以日志打印比较乱。

在这里插入图片描述

结构:

  • 被装饰者抽象接口(Food):提供基础功能方法,和装饰方法接口。
  • 具体的被装饰者(Noodles):继承抽象类,实现方法接口。
  • 装饰者公共类(Decorator):实现统一的装饰方法。
  • 具体的修饰者类:定制化装饰者属性。

使用场景:在软件开发过程中,有时想用一些现存的组件(已经定义好的对象)。这些组件可能只是完成一些核心功能。但在不改变其架构的情况下,可以动态地扩展其功能。所以这些都可以采用装饰模式来实现。

特点:

装饰者设计模式是通过组合+继承的形式实现的。

装饰类和被装饰类可以独立发展,不会相互耦合。

装饰模式是继承的一个替代模式,装饰模式可以动态扩展一个实现类的功能。

猜你喜欢

转载自blog.csdn.net/weixin_44477424/article/details/131905486