修饰模式是一种动态地往一个对象中加入新的行为的设计模式。继承是对现有类进行扩充,用来添加基类功能,该扩充动作是在编译期完毕。而修饰模式是对一个对象进行扩充。从而达到修饰的目的,该修饰动作是在执行期完毕。装饰模式的UML图例如以下:

【设计模式】装饰模式_装饰模式

以下是一个用C++编写的关于描写叙述一个人的演示样例程序,并使用了装饰模式。

#include <iostream>
#include <string>
   
using namespace std;
   
// Component
class Person {
public:
    virtual void Describe() = 0;
    virtual ~Person()    // 存在继承关系,须要使用虚析构函数
    {}
};
   
// ConcreteComponent
class Student : public Person {
public:
    Student(const string &n) : name(n)
    {}
    // 重写虚函数
    void Describe()
    {
        cout << "Name : " << name << endl;
    }
private:
    string name;
};
   
// Decorator
class Decorator : public Person {
public:
    Decorator(Person *p)
    {
        person = p;
    }
   
    void Describe()
    {
        person->Describe();  // 调用被修饰对象自身的方法
    }
 
private:
    Person *person; // 保存须要被修饰的对象
};
  
// ConcreteDecorator
class DecoratorAge : public Decorator {
public:
    DecoratorAge(Person *p, int a) : Decorator(p), age(a)
    {}
   
    void Describe()
    {
        Decorator::Describe();
        cout << "Age : " << age << endl;  // 修饰
    }
private:
    int age;
};
  
// ConcreteDecorator
class DecoratorSex : public Decorator {
public:
    DecoratorSex(Person *p, const string &s) : Decorator(p), sex(s)
    {}
   
    void Describe()
    {
        Decorator::Describe();
        cout << "Sex : " << sex << endl;  // 修饰
    }
private:
    string sex;
};
   
int main()
{
    Student s("Nestle");
       
    cout << "无修饰:" << endl;
    s.Describe();
    cout << endl;
   
    cout << "修饰年龄:" << endl;
    DecoratorAge decoratorAge(&s, 24);      // 修饰器
    decoratorAge.Describe();
    cout << endl;
   
    cout << "修饰性别:" << endl;
    DecoratorSex decoratorSex(&s, "man");   // 修饰器
    decoratorSex.Describe();
    cout << endl;
   
    cout << "同一时候修饰年龄和性别:" << endl;
    DecoratorSex decoratorAll(&decoratorAge, "man");    // 修饰器
    decoratorAll.Describe();
    cout << endl;
   
    system("pause");
    return 0;
}

执行结果:

【设计模式】装饰模式_#include_02

在这个样例中,我把人作为修饰对象,并从Person抽象类(在装饰模式中被称为Component)派生出一个Student非抽象类(在装饰模式中被称为ConcreteComponent)。

该类中有一个描写叙述自己的成员函数Describe,但描写叙述的内容十分简单,所以须要使用装饰模式对描写叙述内容进行修饰扩充。接下来在从Person类派生出一个Decorator类,这个类是其他修饰器类的基类,也就是说。真正对Student对象进行修饰的类必须继承自Decorator类。在Decorator类中保存有被修饰对象的指针,我们须要用这个指针完毕被修饰对象自身的操作。我在这个样例中构建了两个详细的修饰类(在装饰模式中被称为ConcreteDecorator)。一个是修饰Student年龄的DecoratorAge类,还有一个是修饰Student性别的DecoratorSex类。它们运行完被修饰对象原有的操作后。就运行自己的修饰行为。分别输出年龄和性别,从而达到修饰目的。在用户代码中,实例化了一个Student对象和三个修饰器,修饰器可任意的对Student对象进行修饰。

装饰模式的优点在于,对一个对象功能的扩充不须要在该对象所属类中加入代码。仅仅须要单独建立一个或几个类,用这些类来修饰对象。这样便有效地把类的核心职责和装饰功能分离开来。

而且修饰方法很灵活,在上面的样例中,我们能够仅仅修饰年龄或对象或同一时候修饰。形成一个修饰链。

參考:

《大话设计模式》第6章

维基百科