0

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 のオブジェクトを作成する必要があります。次に、(DecoratorType 内の) AbstractType へのポインターの構成を使用して装飾します。具体的なオブジェクトを作成し、新しい装飾されたオブジェクトを次々と作成すると、うまく機能します..

DecoratorType が 1 行のコード (サンプル コードのコメント アウトされた行) でコンポジションを使用してオブジェクトを装飾できるようにするには、何をする必要がありますか? このようなものは、「現実の世界」でまったく役に立ちますか? 私は(明らかに)デザインパターンを使用した経験があまりありません..なので、どの機能を目指すべきかを理解するのは難しいです.

編集:

以下は、基本的なポインターで動作するバージョンです (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;
};
4

2 に答える 2

4
FirstDecoratorType firstDynamicDec (SecondConcreteType()); 

これの問題は、オブジェクトを定義していないことです。代わりに、関数を宣言します。このサイトでMost-vexing-parse in C++ を探してください。多くのトピックが表示されます。

簡単な説明:関数名はfirstDynamicDec戻り値の型でFirstDecoratorTypeあり、引数を返さない関数であるパラメーターをSecondConcreteType取ります。

于 2013-01-05T16:05:23.490 に答える
1

一番の問題は、

FirstDecoratorType firstDynamicDec (SecondConcreteType()); 

オブジェクトを宣言するのではなく、関数を宣言します。これは、C++の最も厄介な解析と呼ばれます。

しかし、それを回避したとしても、一時オブジェクト ( によって作成されたものなどSecondConcreteTpe()) は式の最後までしか存在しないという問題があるため、その中のポインターは、FirstDecoratorType何か有用なことを行う前に無効になります。
これは、スマート ポインターを使用して装飾された型をデコレーター内に保持することで解決できます (たとえば、std::unique_ptr)。これにより、デコレーターは装飾された型をクリーンアップする責任を負います。

于 2013-01-05T16:10:52.940 に答える