当前位置: 首页 > article >正文

C++设计模式(装饰模式)

一、介绍

1.动机

在某些情况下我们可能会“过度地使用继承来扩展对象的功能”,由于继承为类型引入的静态特质,使得这种扩展方式缺乏灵活性;并且随着子类的增多(扩展功能的增多),各种子类的组合(扩展功能的组合) 会导致更多子类的膨胀。

如何使“对象功能的扩展”能够根据需要来动态地实现?同时避免“扩展功能的增多”带来的子类膨胀问题,从而使得任何“功能扩展变化”所导致的影响将为最低?

 

2.定义

动态(组合)地给一个对象增加一些额外的职责。就增加功能而言,Decorator模式比生成子类(继承) 更为灵活(消除重复代码并减少子类个数)。——GOF

 

3.结构图

0167c308773d43d48182a8d411022685.jpeg

 

4.要点总结

通过采用组合而非继承的手法,Decorator模式实现了在运行时动态扩展对象功能的能力,而且可以根据需要扩展多个功能,避免了使用继承带来的“灵活性差”和“多子类衍生问题”。

Decorator类在接口上表现为is-a的继承关系,即Decorator类继承了Component类所具有的接口;但在实现上又表现为has-a的组合关系,即Decorator类又使用了另外一个Component类。

Decorator模式的目的并非解决“多子类衍生的多继承”问题,其应用的要点在于解决“主体类在多个方向上的扩展功能”——是为“装饰”的含义。

 

 

二、装饰模式

1.概念

装饰模式允许在不改变现有对象结构的情况下,动态地为对象添加额外的功能。

①装饰模式的优点:

  • 提供了比继承更灵活的功能扩展机制。
  • 通过使用不同的具体装饰类可以创造出很多不同行为的组合。

②装饰模式的缺点:

  • 由于需要引入更多的类和对象,可能会增加系统的复杂度。
  • 如果装饰器的层次结构设计不当,可能会导致维护困难。

 

2.实现要点

装饰模式实现要点:

  • 抽象构件:定义了对象的接口,所有的具体构件都必须继承或实现这个接口。
  • 具体构件:实现抽象构件的具体类,它是被装饰的对象。
  • 抽象装饰:继承并组合抽象构件,可以通过其子类扩展具体构件的功能。
  • 具体装饰:实现抽象装饰的相关方法,可传入具体构件对象以扩展其功能。

抽象装饰器使用组合是为了传入主体来实现装饰,使用继承是为了规范接口,同时保证包装后不改变原对象的本质。

 

3.示例

//抽象构件
class Coffee {
public:
	virtual string getName() = 0;
	virtual double cost() = 0;
	virtual ~Coffee() {}

};

//具体构件
class Espresso :public Coffee {
public:
	virtual string getName() override {
		return "Espresso";
	}
	virtual double cost() override {
		return 2.5;
	}
};

//具体构件
class Americano :public Coffee {
public:
	virtual string getName() override {
		return "Americano";
	}
	virtual double cost() override {
		return 3.0;
	}
};

//具体构件
class Latte :public Coffee {
public:
	virtual string getName() override {
		return "Latte";
	}
	virtual double cost() override {
		return 3.5;
	}
};

//抽象装饰器
class CoffeeDecorator :public Coffee {
protected:
	Coffee* coffee;
public:
	CoffeeDecorator(Coffee* cof) :coffee(cof) {
	}
	virtual ~CoffeeDecorator() {
		delete coffee;
	}
};

//具体装饰器
class SugarDecorator : public CoffeeDecorator {
public:
	SugarDecorator(Coffee* cof) :CoffeeDecorator(cof) {}
	virtual string getName() override {
		return coffee->getName() + " Sugar";
	}
	virtual double cost() override {
		return coffee->cost() + 0.2;
	}
};

//具体装饰器
class MilkDecorator :public CoffeeDecorator {
public:
	MilkDecorator(Coffee* cof) :CoffeeDecorator(cof) {}
	virtual string getName() override {
		return coffee->getName() + " Milk";
	}
	virtual double cost() override {
		return coffee->cost() + 0.5;
	}
};

//具体装饰器
class CreamDecorator :public CoffeeDecorator {
public:
	CreamDecorator(Coffee* cof): CoffeeDecorator(cof) {}
	virtual string getName() override {
		return coffee->getName() + " Cream";
	}
	virtual double cost() override {
		return coffee->cost() + 0.8;
	}
};

测试代码:

Coffee* espresso = new Espresso();
cout << espresso->getName() << " " << espresso->cost() << endl;
espresso = new SugarDecorator(espresso);
cout << espresso->getName() << " " << espresso->cost() << endl;
espresso = new MilkDecorator(espresso);
cout << espresso->getName() << " " << espresso->cost() << endl;
delete espresso;

Coffee* americano = new Americano();
cout << americano->getName() << " " << americano->cost() << endl;
Coffee* americano1 = new SugarDecorator(americano);
cout << americano1->getName() << " " << americano1->cost() << endl;
Coffee* americano2 = new CreamDecorator(americano1);
cout << americano2->getName() << " " << americano2->cost() << endl;
delete americano2;

Coffee* latte = new Latte();
cout << latte->getName() << " " << latte->cost() << endl;
MilkDecorator* milk = new MilkDecorator(latte);
cout << milk->getName() << " " << milk->cost() << endl;
CreamDecorator* cream = new CreamDecorator(milk);
cout << cream->getName() << " " << cream->cost() << endl;
delete cream;

输出结果:

Espresso 2.5
Espresso Sugar 2.7
Espresso Sugar Milk 3.2
Americano 3
Americano Sugar 3.2
Americano Sugar Cream 4
Latte 3.5
Latte Milk 4
Latte Milk Cream 4.8

 

 


http://www.kler.cn/a/416697.html

相关文章:

  • Docker 清理镜像策略详解
  • 远程协助软件Todesk免费版有什么限制
  • BiGRU:双向门控循环单元在序列处理中的深度探索
  • 学习日记_20241126_聚类方法(自组织映射Self-Organizing Maps, SOM)
  • docker使用(镜像、容器)
  • FRU文件
  • Java中的运算符“instanceof“详解
  • pycharm链接neo4j数据库(简单)
  • 系统思考—结构影响行为
  • ubuntu24.04 python环境
  • jdk8没有InputStream.transferTo()
  • 鸿蒙千帆启新程,共绘数字生态蓝图
  • 腾讯阅文集团Android面试题及参考答案
  • 【查询目录】.NET开源 ORM 框架 SqlSugar 系列
  • 在VMware虚拟机上安装Kali Linux的详细教程(保姆级教程)
  • 腾讯微众银行大数据面试题(包含数据分析/挖掘方向)面试题及参考答案
  • 鸿蒙NEXT元服务:利用App Linking实现无缝跳转与二维码拉起
  • Linux系统编程——进程替换
  • Python异步编程新写法:asyncio模块的最新实践
  • K8s的API资源对象NetworkPolicy
  • BiGRU:双向门控循环单元在序列处理中的深度探索
  • SAP Native SQL 的简单说明
  • C#里怎么样LINQ来从数组里获得大于某数的值?
  • GPT诞生两周年,AIPC为连接器带来什么新变化?
  • vue3 ts button 组件封装
  • Docker 清理镜像策略详解