在软件组件的设计中,如果责任划分的不清晰,使用继承得到的结果往往是随着需求的变化,子类急剧膨胀,同时充斥着重复代码,这时候的关键是划清责任。
装饰模式允许想一个现有的对象添加新的功能,同时又不改变其结构,它是作为现有的类一个包装。这种模式创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。
1. 介绍
意图:动态(组合)地给一个对象增加一些额外的职责。就增加功能而言,Decorator模式比生成子类(继承)更为灵活(消除重复代码 & 减少子类个数)。
主要解决:一般的,我们为了扩展一个类经常使用继承方式实现,由于继承类引入静态特性,并且随着扩展功能的增多,子类会很膨胀。
何时使用:再不想增加很多子类的情况下扩展类
如何解决:将具体功能职责划分,同时继承装饰着模式。
关键代码:1、component类充当抽象角色,不应该具体实现。2、修饰类引用和继承component类,具体扩展类重写父类方法。
应用实例:1、孙悟空有72变,当他变成庙宇后,他的根本还是一只猴子,但是他又有了庙宇的功能。2、不论衣服换有没有画框都可以挂在墙上,但是通常都是有画框的,并且实际上是画框挂在墙上。再挂在墙上之前,画可以被蒙上玻璃,装到框子里;这时画、玻璃和画框变成了一个整体。
优点:装饰类和被装饰类可以独立发展,不会相互耦合,装饰模式是继承的一个替代模式,装饰模式可以动态扩展一个实现类的功能。
缺点:多层装饰比较复杂。
使用场景:1、扩展一个类的功能。2、动态增加功能,动态撤销。
注意事项:可替代继承类。
2.实例
们将创建一个 Shape 接口和实现了 Shape 接口的实体类。然后我们创建一个实现了 Shape 接口的抽象装饰类 ShapeDecorator,并把 Shape 对象作为它的实例变量。
RedShapeDecorator 是实现了 ShapeDecorator 的实体类。
DecoratorPatternDemo 类使用 RedShapeDecorator 来装饰 Shape 对象。
2.1. C++实现
#include <stdio.h>
#include <vector>
class shape {
public:
virtual void draw() = 0;
virtual ~shape(){}
};
class circle : public shape {
public:
void draw() {
printf("Circle draw\n");
}
};
class rectangle : public shape {
public:
void draw() {
printf("Rectangle draw\n");
}
};
class shapeDecorator : public shape {
protected:
shape* decorShape;
shapeDecorator(shape* decorator): decorShape(decorator){}
};
class redShapeDecorator : public shapeDecorator {
public:
redShapeDecorator(shape* redDecorShape): shapeDecorator(redDecorShape){}
void draw(){
decorShape->draw();
printf("Red decorator\n");
}
};
class blueShapeDecorator : public shapeDecorator {
public:
blueShapeDecorator(shape* blueDecorShape) : shapeDecorator( blueDecorShape){}
void draw(){
decorShape->draw();
printf("Blue decortor\n");
}
};
#include<stdio.h>
#include "game.h"
int main(int argc, char** argv)
{
circle* cir = new circle();
cir->draw();
redShapeDecorator* redDecorator = new redShapeDecorator(cir);
redDecorator->draw();
while (1);
return 0;
}
3. 小结
通过采用组合而非继承的手法,decorator模式实现了再运行时动态扩展对象功能的能力,而且可以根据需要扩展多个功能。避免了使用继承带来的“灵活性差”和“多子类衍生问题”。
Decorator类的接口上表现为is-a component的继承关系,机decorator类继承了component类所具有的的接口。但在实现上又表现为has-a component的组合关系,即decorator类又使用了另外一个component。
Decorator模式的目的并非解决“多子类衍生的多继承”问题,decorator模式应用的要点在于解决“主题类在多个方向上的扩展功能”—是为“装饰”的含义。