装饰模式(decorator)
装饰器模式(Decorator)
1、作用
引入一个设计原则:类应该对扩展开发,对修改关闭。简单的说,就是允许我们的我们的类进行扩展,在不修改现有代码的情况 下,适应新的行为改变。
当实现好的类有了新的需求,不考虑重用的话,会直接修改(现在写代码都这样,没有满足开闭原则的修改关闭原则),如果考虑代码的重用,以面向对象的设计思想,多数会想到使用继承,增加新添加的需求,但是如果需求很多,继承类的层次就很深,不方便维护和使用。使用装饰器模式,可以满足新加需求的功能,同时照顾的重用代码,并且避免继承的层次很深。
对原有的输出进行处理得到需要的输出(修饰),而不是修改原点代码,来改变原来代码的输出。这个模式最能够用到编写的脚本上,扩展脚本的功能。
2、实现方式
假设要实现一个简单的打印功能,实用了一个抽象类AbsPrint定义了接口,同时实现了一个具体的打印类BasePrint类,完成打印的基本功能。
但是后续需要添加新的打印需求,比如在打印内容的前后增加"*"和给打印内容加“()”。前面已经分析过,如果直接使用继承的方式,会导致类的层次很深,比利于后期维护,并且在设计模式中:Favor object composition over class inheritance,所以使用装饰器模式是一个比较好的方法(装饰类与原有类是一个关联关系),在不改变原有接口的情况下,添加新的功能,原有接口输出的内容进行处理。
使用Decorator模式,要添加一个中间类:AbsDecorator,这个类唯一功能就是封装一个AbsPrint对象(有的像),从AbsDecorator扩展出两个装饰类,AddBrackets和AddStar类来实现新增的功能。
装饰器可以嵌套使用(即使用AddBrackets又使用AddStart)
3、C++代码
print.h
#include <iostream>
#ifndef __PRINT__H__
#define __PRINT__H__
using namespace std;
class AbsPrint {
public:
AbsPrint() = default;
virtual ~AbsPrint() = default;
virtual void print(const string &str) = 0;
};
class BasePrint : public AbsPrint { // 已有的功能,下面的都是新增的需求
public:
void print(const string &str) override {
cout<<str;
}
};
class AbsDecorator : public AbsPrint { // 这个类的唯一目的就是封装AbsPrint对象,这样可以避免每个装饰器类都加这个成员。
public:
AbsDecorator(AbsPrint *p) : p(p) {}
~AbsDecorator() { delete p; }
protected:
AbsPrint *p;
};
class AddBrackets : public AbsDecorator { // 添加换行符的装饰器
public:
AddBrackets(AbsPrint *p):AbsDecorator(p){}
void print(const string &str) override {
cout<<"(";
p->print(str);
cout<<")";
}
};
class AddStar : public AbsDecorator { // 首尾添加*的装饰器
public:
AddStar(AbsPrint *p): AbsDecorator(p) {}
void print(const string &str) override {
cout<<"*";
p->print(str);
cout<<"*";
}
};
#endif
test.cc
#include <iostream>
#include "print.h"
using namespace std;
int main() {
AbsPrint *p1 = new BasePrint;
p1->print("hello world!"); // 直接使用基本的功能
cout<<endl;
AbsPrint *p2 = new AddStar(new BasePrint);
p2->print("hello world!"); // 使用了添加"*"的装饰器
cout<<endl;
AbsPrint *p3 = new AddBrackets(new BasePrint);
p3->print("hello world!"); // 使用了添加"()"的装饰器
cout<<endl;
AbsPrint *p4 = new AddBrackets(new AddStar(new BasePrint));
p4->print("hello world!"); // 同时使用了加"*"和加"()"的装饰器
cout<<endl;
return 0;
}
输出: