前三种设计模式属于组件协作类模式,后面两篇带来另一种类型的设计模式
1. 情景与意图
有这样一个场景,一个村庄修建房屋,每户人家装修的房子都是不一样的,比如有的带游泳池,有的带车库,有的带花园等等。如果说我们需要实现每个房子的结构,后面可能会建造更多的房子,更多的组合方式,如果采用继承的方式,需要多少个类呢?
单独泳池房子+当杜车库房子+单独花园房子+泳池&花园+花园&车库+…………这是一个阶乘的数量。因此子类非常的多。
这便是一个问题,在某些情况下我们可能会“过度地使用继承来扩展对象的功能”,使得这种扩展方式缺乏灵活性; 并且随着子类的增多,各种子类的组合会导致更多子类的膨胀。
1) 如何动态地实现对象的扩展呢?
2)在 1 的同时避免“扩展功能的增多”带来的子类膨胀
此时我们可以采用装饰器模式来实现。装饰者模式采取组合的方式。
2. 装饰器模式
允许向一个现有的对象添加新的功能,同时又不改变其结构。
一般我们给对象添加新的功能可能会通过继承的方式来解决,但是呢,继承会带来的问题就是,子类越来越多且会越来越臃肿。 我们知道在七大设计原则中有一条就是【组合/聚合复用原则】。我们应该优先使用组合而不是继承,装饰器模式在这个原则表现的就很强烈,
3. 代码实现房子的装饰
下面我们用代码来看看装饰器模式:
首先我们先抽象出房子,并且实现一个具体的房子类
// 抽象的房子
class DPAbstractHouse {
public:
// 展示一下构造
virtual void showStructure() = 0;
};
// 具体的一个房屋类
// .h
// 这里只是简单的实现一个房子类,实际项目中不止一个,
// 我们要面向抽象编程而不是实现编程
class DPHouse : public DPAbstractHouse {
public:
// 展示一下构造
virtual void showStructure();
};
// .cpp
void DPHouse::showStructure() {
std::cout << "的房子" << std::endl;
}
下面来实现抽象的装饰器。这里可能不太好理解,先看看代码。
这里抽象的装饰器继承了抽象的房屋类,是因为我们定义接口的规范,例如showStructure()
这个方法。不理解,我们继续往下走。
class DPAbstractDecorator : public DPAbstractHouse {
public:
DPAbstractDecorator(DPAbstractHouse* house);
virtual void showStructure();
protected:
DPAbstractHouse* _house;
};
实现具体的装饰器:
class DPGardenDecorator :public DPAbstractDecorator {
public:
DPGardenDecorator(DPAbstractHouse* house);
virtual void showStructure();
};
class DPSwimmingPoolDecorator :public DPAbstractDecorator {
public:
DPSwimmingPoolDecorator(DPAbstractHouse* house);
virtual void showStructure();
};
class DPGarageDecorator :public DPAbstractDecorator {
public:
DPGarageDecorator(DPAbstractHouse* house);
virtual void showStructure();
};
// .cpp
DPGardenDecorator::DPGardenDecorator(DPAbstractHouse* house)
:DPAbstractDecorator(house) {
}
void DPGardenDecorator::showStructure() {
std::cout << "带花园" << std::endl;
_house->showStructure();
}
DPSwimmingPoolDecorator::DPSwimmingPoolDecorator(DPAbstractHouse* house)
:DPAbstractDecorator(house) {
}
void DPSwimmingPoolDecorator::showStructure() {
std::cout << "带泳池" << std::endl;
_house->showStructure();
}
DPGarageDecorator::DPGarageDecorator(DPAbstractHouse* house)
:DPAbstractDecorator(house) {
}
void DPGarageDecorator::showStructure() {
std::cout << "带车库" << std::endl;
_house->showStructure();
}
来,我们使用一下:
int main() {
DPHouse* house = new DPHouse();\
// 带泳池的房子
DPAbstractDecorator *spHouse = new DPSwimmingPoolDecorator(house);
// spHouse->showStructure();
// 还可以进行组合,带泳池和车库的房子
DPAbstractDecorator* gSPHouse = new DPGarageDecorator(spHouse);
gSPHouse->showStructure();
return 0;
}
看到这里呢,其实你心中可能在想,这不是套娃嘛。
4. 总结
在上面的例子中通过采用组合而非继承的手法, 装饰器模式实现了在运行时动态扩展对象功能的能力,而且可以根据需要扩展多个功能。避免了使用继承带来的“灵活性差”和“多子类衍生问题”。
装饰器模式的目的并非解决“多子类衍生的多继承”问题, 装饰器模式应用的要点在于解决“主体类在多个方向上的扩展功能”——是为“装饰”的含义。装饰类和被装饰类可以独立发展,不会相互耦合,装饰模式是继承的一个替代模式,装饰模式可以动态扩展一个实现类的功能。
装饰器设计模式的代码见【装饰器模式C++源码】