如何使用C ++中的装饰器模式在单行代码中装饰对象?

时间:2013-01-05 15:54:00

标签: c++ design-patterns decorator

我正在学习Head First Design Patterns book中的装饰器模式,这是我编写的代码(C ++)以使模式起作用:

#include <iostream>


class AbstractType
{
public: 
    virtual double value() const = 0;
};


class FirstConcreteType
    :
    public AbstractType
{
public: 
    double value() const 
    {
        return 1; 
    }
};

class SecondConcreteType
    : 
    public AbstractType
{
public:
    double value() const
    {
        return 2;
    }
};

class DecoratorType
    :
    public AbstractType
{
    const AbstractType* decoratedObject_; 

public:

    DecoratorType(const AbstractType& abstractObject)
        :
    decoratedObject_(&abstractObject)
    {}

    DecoratorType(const DecoratorType& decoratorObject)
        :
    decoratedObject_(&decoratorObject)
    {}

    virtual double value() const = 0; 

    const AbstractType& getObject() const
    {
        return *decoratedObject_; 
    }
};

class FirstDecoratorType
    :
    public DecoratorType
{
public:
    FirstDecoratorType(const AbstractType& abstractObject)
        :
    DecoratorType(abstractObject)
    {}

    FirstDecoratorType(const DecoratorType& decoratorObject)
        :
    DecoratorType(decoratorObject)
    {}

    double value() const
    {
        const AbstractType& object = getObject(); 

        return 1 + object.value(); 
    }
};

class SecondDecoratorType
    :
    public DecoratorType
{
public:
    SecondDecoratorType(const AbstractType& abstractObject)
        :
    DecoratorType(abstractObject)
    {}

    SecondDecoratorType(const DecoratorType& decoratorObject)
        :
    DecoratorType(decoratorObject)
    {}

    double value() const
    {
        const AbstractType& object = getObject(); 

        return 2 + object.value(); 
    }
};

using namespace std;

int main()
{
    // When I decorate sequentially, it works fine

    SecondConcreteType secondConc;

    FirstDecoratorType firstDec(secondConc); 
    cout << firstDec.value() << endl;

    SecondDecoratorType secondDec(firstDec); 
    cout << secondDec.value() << endl;

    FirstDecoratorType firstDecSecond (secondDec); 
    cout << firstDecSecond.value() << endl; 

    // Decorating in a single line, messes things up, since there is no
    // constructor taking the value argument defined.  
    //FirstDecoratorType firstDynamicDec (SecondConcreteType()); 
    //cout << firstDynamicDec.value() << endl;

    return 0;
};

在主程序中,必须首先创建ConcreteType的对象,然后使用指向AbstractType的指针(在DecoratorType中)的组合来装饰它。它工作正常,如果我创建具体对象,并一个接一个地创建新的装饰对象..

为了让DecoratorType能够使用单行代码中的合成来装饰对象(示例代码中注释掉的行),我需要做些什么?这样的事情在“现实世界”中会有用吗?我(显然)在使用设计模式方面没有太多经验。所以我很难看到我应该瞄准的功能。

编辑:

这是一个使用基本指针的版本(valgrind显示没有内存泄漏,并声明不存在内存泄漏):

#include <iostream>


class AbstractType
{
    public: 
        virtual double value() const = 0;

        virtual ~AbstractType() {}; 
};

class FirstConcreteType
:
    public AbstractType
{
    public: 
        double value() const 
        {
            return 1; 
        }
};

class SecondConcreteType
: 
    public AbstractType
{
    public:
        double value() const
        {
            return 2;
        }
};

class DecoratorType
:
    public AbstractType
{
    const AbstractType* decoratedObject_; 
    bool own_;

    public:

        DecoratorType(const AbstractType& abstractObject)
            :
                decoratedObject_(&abstractObject), 
                own_(false)
        {}

        DecoratorType(const DecoratorType& decoratorObject)
            :
                decoratedObject_(&decoratorObject), 
                own_(false)

        {}

        DecoratorType (AbstractType* abstractPtr)
            : 
                decoratedObject_(abstractPtr), 
                own_(true)
        {}

        DecoratorType (DecoratorType* decoratorPtr)
            :
                decoratedObject_(decoratorPtr), 
                own_(true)
        {}

        virtual ~DecoratorType()
        {
            if (own_)
            {
                delete decoratedObject_; 
                decoratedObject_ = 0;
            }
        }

        virtual double value() const = 0; 

        const AbstractType& getObject() const
        {
            return *decoratedObject_; 
        }
};

class FirstDecoratorType
:
    public DecoratorType
{
    public:
        FirstDecoratorType(const AbstractType& abstractObject)
            :
                DecoratorType(abstractObject)
        {}

        FirstDecoratorType(const DecoratorType& decoratorObject)
            :
                DecoratorType(decoratorObject)
        {}

        FirstDecoratorType (AbstractType* abstractPtr)
            :
                DecoratorType(abstractPtr)
        {}

        FirstDecoratorType (FirstDecoratorType* decoratorPtr)
            :
                DecoratorType(decoratorPtr)
        {}


        double value() const
        {
            const AbstractType& object = getObject(); 

            return 1 + object.value(); 
        }
};

class SecondDecoratorType
:
    public DecoratorType
{
    public:
        SecondDecoratorType(const AbstractType& abstractObject)
            :
                DecoratorType(abstractObject)
        {}

        SecondDecoratorType(const DecoratorType& decoratorObject)
            :
                DecoratorType(decoratorObject)
        {}

        SecondDecoratorType (AbstractType* abstractPtr)
            :
                DecoratorType(abstractPtr)
        {}

        SecondDecoratorType (SecondDecoratorType* decoratorPtr)
            :
                DecoratorType(decoratorPtr)
        {}

        double value() const
        {
            const AbstractType& object = getObject(); 

            return 2 + object.value(); 
        }
};

using namespace std;

int main()
{
    // When I decorate sequentially, it works fine

    SecondConcreteType secondConc;

    FirstDecoratorType firstDec(secondConc); 
    cout << firstDec.value() << endl;

    SecondDecoratorType secondDec(firstDec); 
    cout << secondDec.value() << endl;

    FirstDecoratorType firstDecSecond (secondDec); 
    cout << firstDecSecond.value() << endl; 

    // Decorating in a single line, messes things up, since there is no
    // constructor taking the value argument defined.  
    FirstDecoratorType firstDynamicDec (new SecondDecoratorType (
           new FirstDecoratorType (new SecondConcreteType()))); 

    cout << firstDynamicDec.value() << endl;

    return 0;
};

2 个答案:

答案 0 :(得分:4)

FirstDecoratorType firstDynamicDec (SecondConcreteType()); 

这个问题是它没有定义一个对象。相反,它声明一个函数。在这个网站上查找C ++中的 most-vexing-parse ,你会得到很多关于它的主题。

简短说明:函数名称为firstDynamicDec,其返回类型为FirstDecoratorType,它接受​​的参数又是一个返回SecondConcreteType且不带参数的函数。

答案 1 :(得分:1)

第一个问题是

FirstDecoratorType firstDynamicDec (SecondConcreteType()); 

根本不会声明一个对象,而是一个函数。这称为C ++的most vexing parse

但即使你解决了这个问题,你也会遇到临时对象(例如SecondConcreteTpe()创建的)仅存在于表达式结尾之前的问题,因此FirstDecoratorType中的指针无效在你做任何有用的事情之前。
您可以使用智能指针在装饰器中保存装饰类型来解决此问题(例如,std::unique_ptr)。这使得装饰者负责清理装饰类型。