1. 何为装饰者模式?
不改变原有类的结构,动态地给其对象添加新功能。
2. 为什么需要装饰者模式?
面向对象编程原则之一:开闭原则。
即开放扩展、关闭修改(不修改已有代码的情况下,通过扩展的方式增加新功能而满足需求的变化)。该原则旨在提高代码的复用性、可维护性,降低代码耦合度。
于是就有了装饰者模式。
3. 详细说明+例子
开发过程中发现有新需求,需要增加原有类的功能,根据开闭原则,不允许直接修改原有类。
一种解决方式是:使用继承,在子类中添加新功能。
例子如下(例子中的黑色箭头表示继承,粉色箭头表示指针指向):
某汽车公司有两款车型:CarA和CarB,第一代CarA_1st和CarB_1st都只有各自的基础功能,如图1.
现在公司为CarA、CarB增加新功能升级成第二代,两款车型都分别推出高配和低配,如图2.
可见若通过继承的方式升级第二代车会导致子类过多,若第一代推出更多车型,则第二代会产生更多的子类。
显然该场景中,通过继承这种方式来添加新的功能并不好。
使用装饰者模式改进
做法是:
定义一个装饰者类继承自Car类,在其中定义Car类型指针成员pCar,因为Car为基类,所以该指针pCar可以指向其子类CarA_1st或者CarA_2st,从而获取其中的基础功能,然后在获取基础功能的基础上,可以添加新功能,即装饰,由此不改变原有类结构,同时大大减少子类数量。如图3所示。
代码示例:
/* 抽象基类 */
class Car {
public:
virtual void func() = 0;
private:
};
/* 第一代车 */
class CarA_1st : public Car {
public:
virtual void func() {
cout << "基础功能A" << endl;
}
private:
};
class CarB_1st : public Car {
public:
virtual void func() {
cout << "基础功能B" << endl;
}
private:
};
/* 装饰者类,用于创建第二代车 */
class CarDecoratorHigh : public Car { // 第二代高配车
public:
CarDecoratorHigh(Car* p) : pCar(p) {}
virtual void func() {
pCar->func(); // 将原有的基础功能拿过来
cout << "高配功能" << endl;
}
private:
Car* pCar; // 基类指针,可指向派生类
};
class CarDecoratorLow : public Car { // 第二代低配车
public:
CarDecoratorLow(Car* p) : pCar(p) {}
virtual void func() {
pCar->func(); // 将原有的基础功能拿过来
cout << "低配功能" << endl;
}
private:
Car* pCar; // 基类指针,可指向派生类
};
/* 测试 */
void test() {
Car* pCarA_1st = new CarA_1st; // 创建第一代CarA
Car* pCarA_2nd_high = new CarDecoratorHigh(pCarA_1st); // 使用装饰类将第一代CarA升级成第二代CarA高配版
pCarA_2nd_high->func();
delete pCarA_1st;
delete pCarA_2nd_high;
}
为什么装饰类也要继承自基类呢?
结合图3和代码来看。
万一将来还有装饰类B在已有装饰类A基础上再装饰,若装饰类A不是Car的子类,则装饰类B无法使用Car*指针获得装饰类A的已有功能。 且若装饰类A不是Car的子类,则它就不能使用基类Car的虚函数func()来实现多态,也就不能在运行时动态地给原有对象添加额外的功能。