顾名思义,装饰模式就是在现有类的基础上添加一些装饰。以这篇博客中提供的背景为例,假设现在华为以及小米手机厂商生产出来了一批手机,但是需要给这些手机添加一些装饰,比如给华为手机贴钢化膜、给小米手机配上一个手机壳。这其实并不需要再设计一个类,并在这些手机类的基础上添加一些功能,这样做太麻烦了。一个简单的做法就是给这些手机类添加一个装饰类,在这以及类的基础上,额外添加一些装饰。
从上述UML图不难得知,Phone需要作为装饰器类的一个私有成员变量,从而可以对Phone实例对象进行操作。在Past和Mask类中分别负责不同的装饰方法(其实可以把所有的装饰方法都集成在装饰器类中)。
1. 手机类的定义
由于每个手机都需要name成员变量以及show()成员方法,且show()成员方法的内容基本上是一致的,所以将name成员变量以及show()成员方法都集成在基类对象中了,这样可以避免在所有的子类都相中都在重写show()函数。
在继承类中,由于无法访问基类的private属性,因此每个子类的name变量都可以通过基类的构造方法进行定义。
#include <iostream>
#include <string>
using namespace std;
class Phone{
private:
string name;
public:
Phone():name(""){};
Phone(string name):name(name){};
virtual ~Phone(){};
virtual void show(){
cout << "这是" << name << "手机"<< endl;
}
};
// 华为手机
class HuaWei:public Phone{
public:
HuaWei(){};
HuaWei(string name):Phone(name){};
~HuaWei(){};
};
// 小米手机
class XiaoMi:public Phone{
public:
XiaoMi(){};
XiaoMi(string name):Phone(name){};
~XiaoMi(){};
};
2. 装饰器类的实现
在装饰器中也需要重写show()方法,只不过这个show()方法就与其成员变量phone有关了。
// 装饰器
class Decorator:public Phone{
private:
Phone* phone;
public:
Decorator():phone(nullptr){};
Decorator(Phone* phone):phone(phone){};
virtual void show(){
phone->show();
}
};
// 给手机贴膜
class Past:public Decorator{
private:
void padpastring(){
cout << "已经完成手机贴膜" << endl;
}
public:
Past(Phone* phone):Decorator(phone){};
void show(){
Decorator::show();
padpastring();
}
};
// 给手机装上手机壳
class Mask:public Decorator{
private:
void addMask(){
cout << "已经完成手机装壳功能" << endl;
}
public:
Mask(Phone* phone):Decorator(phone){};
void show(){
Decorator::show();
addMask();
}
};
3. 测试程序
测试程序的代码及其实验结果如下:
int main(){
Phone* huawei = new HuaWei("华为");
Phone* xiaomi = new XiaoMi("小米");
// 给华为手机贴膜
Past* past = new Past(huawei);
// 给小米手机装手机壳
Mask* mask = new Mask(xiaomi);
past->show();
mask->show();
return 0;
}