装饰模式(decorator)

发布时间 2023-09-07 18:11:45作者: 下夕阳

装饰器模式(Decorator)

1、作用

引入一个设计原则:类应该对扩展开发,对修改关闭。简单的说,就是允许我们的我们的类进行扩展,在不修改现有代码的情况 下,适应新的行为改变。

当实现好的类有了新的需求,不考虑重用的话,会直接修改(现在写代码都这样,没有满足开闭原则的修改关闭原则),如果考虑代码的重用,以面向对象的设计思想,多数会想到使用继承,增加新添加的需求,但是如果需求很多,继承类的层次就很深,不方便维护和使用。使用装饰器模式,可以满足新加需求的功能,同时照顾的重用代码,并且避免继承的层次很深。

对原有的输出进行处理得到需要的输出(修饰),而不是修改原点代码,来改变原来代码的输出。这个模式最能够用到编写的脚本上,扩展脚本的功能。

2、实现方式

假设要实现一个简单的打印功能,实用了一个抽象类AbsPrint定义了接口,同时实现了一个具体的打印类BasePrint类,完成打印的基本功能。

img

但是后续需要添加新的打印需求,比如在打印内容的前后增加"*"和给打印内容加“()”。前面已经分析过,如果直接使用继承的方式,会导致类的层次很深,比利于后期维护,并且在设计模式中:Favor object composition over class inheritance,所以使用装饰器模式是一个比较好的方法(装饰类与原有类是一个关联关系),在不改变原有接口的情况下,添加新的功能,原有接口输出的内容进行处理。

使用Decorator模式,要添加一个中间类:AbsDecorator,这个类唯一功能就是封装一个AbsPrint对象(有的像),从AbsDecorator扩展出两个装饰类,AddBrackets和AddStar类来实现新增的功能。

装饰器可以嵌套使用(即使用AddBrackets又使用AddStart)

img

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;
}

输出: