装饰器模式——现代C++设计模式


当已经存在一个类,想要扩展他的功能,该怎么办呢?继承?由于单一职责原则,需要将扩展的功能单独分开

使用场景

装饰器模式能够在不修改原始类型(不违反开闭原则)、不产生大量派生类型的情况下扩展现有类的功能。
通常通过组合的形式,包括了动态组合和静态组合

动态装饰器实现

#include<iostream>
#include<vector>
using namespace std;
struct Shape {
	virtual string str() const = 0;
};
struct Circle :Shape{ //继承的类型函数
	float radius;
	explicit Circle(const float radius):radius(radius){}

	string str()const override 
	{
		return "A circle of radius";
	}
};

struct ColoredShape :Shape { //动态装饰器
	Shape& shape;			//将要装饰的引用
	string color;
	ColoredShape(Shape& shape, const string& color)	//初始化时设置将要装饰的对象
		:shape{ shape }, color{ color } {}
	string str()const override 
	{
		return shape.str() + " has the color " + color;
	}
	void make_dark() {
		if (constexpr auto dark = "dark"; !color.starts_with(dark)) 
			color.insert(0, dark);
		//constexpr是c++11新特性,可以将运算放在编译阶段,而不是运行阶段
		//starts_with判断字符串是否为右侧子字符串开头
			
	}
};

int main() {
	Circle circle{ 1 };//生成对象
	ColoredShape red{ circle,"red" };
	cout << red.str()<<endl;
	red.make_dark();
	cout << red.str()<<endl;
	
	return 0;
}

在上边这个例子中,装饰器中包括了原有类的引用,通过传入引用的方法进行是功能扩展,相应的也可以定义用来扩展其他功能的装饰器:如Sizedshape用来修改形状

静态装饰器实现——Mixin继承


#include<iostream>
#include<vector>
using namespace std;
struct Shape {
	virtual string str() const = 0;
};
struct Circle :Shape{ //继承的类型函数
	float radius;
	explicit Circle(const float radius):radius(radius){}

	string str()const override 
	{
		return "A circle of radius  ";
	}
};
//继承自模板参数
template<typename T>struct ColoredShape :T
{
	static_assert(is_base_of_v<Shape, T>, "Template argument must be a Shape"); 
	//判断基类是否为Shape
	string color; 
	string str()const override {
		return T::str() + " has the color:" + color;
	}
	template<class ...Args>  //通过模板实现任意参数传递 
	ColoredShape(string data, Args ...args) :T(forward<Args>(args)...), color{ data } {}

};

template<typename T>struct TransparentShape :T
{
	static_assert(is_base_of_v<Shape, T>, "Template argument must be a Shape");
	string Transparent;
	string str()const override {
		return T::str() + "  has the  Transparent:" + Transparent;
	}
	template<class ...Args>
	TransparentShape(string data, Args ...args) :T(forward<Args>(args)...), Transparent{ data } {}
};

int main() {
	Circle circle{ 1 };//生成对象
	TransparentShape<ColoredShape<Circle>> square{ "1","Blue",3};  //Arg性质能够快速赋值
	cout<<square.str();

	return 0;
}


输出

A circle of radius   has the color;Blue  has the  Transparent:1

可以观察到,静态组合意味着对象及其强化功能是在编译阶段使用模板组合而成的,也就是需要模板继承基类。
例子实现了Minix继承:Mixin继承中,类继承自它的模板参数,相比于普通继承,状态空间会更小,在编译时组合装饰器。
还通过模板实现了接受任意数量的参数。

由于是继承,所以动态装饰器能够访问被装饰对象的所有成员。

总结

  • 动态装饰器可以存储对被装饰对象的引用(如果需要,甚至可以存储整个值!)并
    提供动态(运行时)可组合性,但代价是无法访问底层对象自己的成员。

  • 静态装饰器使用mixin继承(从模板参数继承)在编译时组合装饰器。这虽然失去
    了运行时的灵活性(无法重新组合对象),但允许访问底层对象的成员。这些对象也
    可以通过构造函数转发进行完全初始化。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值