装饰器模式是结构型设计模式。
装饰器是现有类的一个包装,可以在不修改现有类且不增加子类的情况下扩展现有类。
【注】可以实现向一个现有对象添加新的功能,同时又不改变其结构的设计模式,称为结构型模式。
2、为什么使用装饰器模式装饰器模式用于需要对现有类进行扩展的场景。
一般情况下,我们想要扩展现有类还可以声明它的子类,即使用继承的特性达到目的。但是如果我们经常使用增加子类的方法扩展现有类,会造成子类的臃肿膨胀。
二、装饰器模式实例博主最近沉迷在某视频软件上看房车旅行相关的小视频。我们以房车做个例子。
假设某房车生产厂家提供A型房车和C型房车两款房车。两款房车都有各自的一些出厂自带的基础功能。但厂家也给客户提供额外加装的一些功能(假设提供额外加装太阳能电池板和额外加装户外燃气灶台),客户可以根据自己的需要自定义自己的爱车。
在这个工程中,我们使用装饰者模式需要下面几个组件(类):
1)房车产品抽象类RVCar;
2)A型房车具体类A_RVCar;
3)C型房车具体类C_RVCar;
4)房车装饰者抽象类ExtraDecorator;
5)太阳能电池板具体类SolarPanel;
6)户外灶台具体类OutDoorCookTop;
代码实现
1)房车抽象类RVCar
//房车类
class RVCar
{
public:
RVCar() {}
virtual ~RVCar() {}
virtual void ShowFeatures() = 0;
};
2)A型房车具体类,继承类RVCar,具有A型房车出厂自带的基础功能。可以提供A型房车实例。
//具体房车类
class A_RVCar : public RVCar
{
public:
void ShowFeatures()
{
cout << "这是一辆A型房车" << endl;
}
};
3)C型房车具体类,继承类RVCar,具有C型房车出厂自带的基础功能。可以提供C型房车实例。
//具体房车类
class C_RVCar : public RVCar
{
public:
void ShowFeatures()
{
cout << "这是一辆C型房车" << endl;
}
};
4)房车装饰者抽象类ExtraDecorator,继承RVCar;
//额外装修的抽象基类
class ExtraDecorator : public RVCar
{
public:
ExtraDecorator(RVCar* car) : _car(car) {}
virtual ~ExtraDecorator() {}
virtual void ShowFeatures()
{
if (nullptr != _car)
{
_car->ShowFeatures();
}
}
private:
RVCar* _car;
};
5)太阳能电池板具体类SolarPanel,继承类ExtraDecorator,提供给某一辆房车(传入的房车对象指针)加装太阳能电池板的服务,即可以实例化一辆具有太阳能电池板的某型房车。
//太阳能电池板类
class SolarPanel : public ExtraDecorator
{
public:
SolarPanel(RVCar* car) : ExtraDecorator(car) {}
virtual void ShowFeatures()
{
ExtraDecorator::ShowFeatures();
setSolarPanel();
}
private:
void setSolarPanel()
{
cout << "安装了太阳能电池板!房车增加了功能:用太阳能发电!" << endl;
}
};
6)户外灶台具体类SolarPanel,继承类ExtraDecorator,提供给某一辆房车(传入的房车对象指针)加装户外灶台的服务,即可以实例化一辆具有户外灶台的某型房车。
//户外灶台类
class OutDoorCookTop : public ExtraDecorator
{
public:
OutDoorCookTop(RVCar* car) : ExtraDecorator(car) {}
virtual void ShowFeatures()
{
ExtraDecorator::ShowFeatures();
setOutDoorCookTop();
}
private:
void setOutDoorCookTop()
{
cout << "安装了户外灶台!房车增加了功能:户外做饭!" << endl;
}
};
7)客户“买车”,厂家根据客户需求提供车辆
int main()
{
//aCar为一辆基础款A型房车
RVCar* aCar = new A_RVCar();
aCar->ShowFeatures();
cout << endl;
//outCookACar为一辆加装了户外灶台的C型房车
RVCar* outCookACar = new OutDoorCookTop(new C_RVCar());
outCookACar->ShowFeatures();
system("pause");
return 0;
}
【注】为了区别其他结构型设计模式,理解装饰器模式的特征,我根据自己的理解总结几点:
1、装饰器模式的作用是为了生成符合额外增加的功能的对象,所以上述实例中的ExtraDecorator类需要继承RVCar,因为经过装饰的具体对象还是一辆房车,需要给客户返回RVCar的对象指针;
所以我认为一些文章中类似这种使用是不正确的,如果这样使用,为什么还要继承RVCar呢?
//一辆加装了户外灶台的C型房车
ExtraDecorator* outCookACar = new OutDoorCookTop(new C_RVCar());
outCookACar->ShowFeatures();
2、这里解释一下为什么使用装饰器模式而不是扩展子类的方法实现工程。假设使用扩展子类的方法实现这个工程,则我们在上面装饰器组件1)2)3)的基础上还需要:
4)加装太阳能电池板的A型房车,继承类A,用于扩展类A的功能;
5)加装户外燃气灶的A型房车,继承类A,用于扩展类A的功能;
6)加装太阳能电池板的C型房车,继承类C,用于扩展类C的功能;
7)加装户外燃气灶的C型房车,继承类C,用于扩展类C的功能;
可见,厂家如果提供M个额外加装服务,有N个基础车型,想要实现加装服务-车型自由组合。扩展子类法需要扩展M*N个子类,可见十分的不灵活,会造成大量的子类膨胀。而使用装饰者模式则有几种额外服务,则增加几个装饰者子类,有几种车型,则增加几种房车具体类,即只需要扩展M+N个类,需要实例化时灵活“组装”即可。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)