装饰模式笔记
菜鸟教程连接https://www.runoob.com/design-pattern/decorator-pattern.html
UML类图入下 :
在Java的IO流的类图
解决的问题 :
-
想给一个类扩展功能,但是不想继承
-
可以动态扩展功能,撤消功能(不知到体现在哪里)
-
需要给已有的类扩展功能,并且要添加新字段时可用
-
可以改变装饰顺序,参考java的io流
InputStream input = null; input = new BufferedInputStream(new GZIPInputStream(new DataInputStream(new FileInputStream("file.txt")))); input = new GZIPInputStream(new DataInputStream(new BufferedInputStream(new FileInputStream("file.txt"))));
注意点:
- 装饰器需要继承自被装饰者
概括:
- 装饰器需要继承自被装饰者
- 装饰器有一个被装饰者成员变量,重写接口时可以调用该成员变量的函数
用到的地方:
- JDK的IO流
实现:
现在我们要做个画图工具,如上面的类图,目前我们已有一个Shape图形接口
,
两个具体图形类Rect和Circle
,现在我们想要添加一个画红色
图形的功能,但是又不想动那两个图形类(不想继承),于是可以添加一个装饰器类,该装饰器拥有图形的所有功能draw()
,并且还有扩展的功能setRedBorde()
可以画出红色图形,具体做法就是:装饰器实现图形接口,有一个图形成员变量shape
,通过构造函数设置shape
,实现的接口可以直接调用shape->draw()
,于是就可以在装饰器里添加新的功能setRedBorde()
了。
代码如下:
原来已经有的图形接口Shape
和两个具体实现类Rect
,Circle
// 原来已有的图形接口
class Shape : public MajiaoObject {
public :
Shape() { }
~Shape() { }
// 图形接口类的绘制方法
virtual void draw() { }
};
// 具体长方形类
class Rect : public Shape {
public :
int w, h;
Rect() { }
~Rect() { }
virtual void draw() { cout << "矩形绘制算法" << endl; }
};
// 具体圆形类
class Circle : public Shape {
public :
int r, d;
Circle() { }
~Circle() { }
virtual void draw() { cout << "Bresenham画圆算法" << endl; }
};
现在我们要扩展新功能画红色图形
,不想去挨个继承Rect
和Circle
,
于是有了装饰器类
// 装饰器接口,必须继承被装饰者的接口
class ShapeDecorator : public Shape {
public :
// 被装饰的对象
Shape* shape;
// 使用构造设置成员变量
ShapeDecorator(Shape* shape) { this->shape = shape; }
~ShapeDecorator() { }
};
// 实现一个具体的装饰器【红色绘制图形装饰器】
class RedShapeDecorator : public ShapeDecorator {
public :
// 调用父类的构造
RedShapeDecorator(Shape* shape) : ShapeDecorator(shape) { }
~RedShapeDecorator() { }
virtual void draw() {
// 调用被装饰者的draw
if (shape) {
setRedBorde(); // 设置画笔颜色
shape->draw();
}
}
// 给原来的图形类添加一个设置边框为红色的功能,但是不需要继承原来的类
virtual void setRedBorde() { cout << "画笔设置成红色了" << endl; }
};
在调用方就可以嵌套new(装饰对象)
- 类似于java的io流
// 可以实现像 java IO流的嵌套 new
Shape *mainRect = new BackgroudShapeDecorator(new RedShapeDecorator(new Rect())), // 先装饰边框颜色,再装饰背景色
*mainCircle = new RedShapeDecorator(new BackgroudShapeDecorator(new Circle())); // 先装饰背景色,再装饰边框颜色
mainRect->draw();
mainRect->draw();