Я учу шаблон декоратора от Книга Head First Design Patterns , и вот что я кодировал (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;
};
FirstDecoratorType firstDynamicDec (SecondConcreteType());
Проблема в том, что он НЕ определяет объект. Вместо этого это объявляет функция. Ищу наиболее раздражающий-синтаксический анализ в C ++ на этом сайте вы получите много тем.
Краткое объяснение: имя функции firstDynamicDec
чей тип возврата FirstDecoratorType
и он принимает параметр, который снова является функцией, возвращающей SecondConcreteType
и не принимая никаких аргументов.
Первая проблема заключается в том, что
FirstDecoratorType firstDynamicDec (SecondConcreteType());
не объявляет объект вообще, но функцию. Это называется самый неприятный разбор C ++.
Но даже когда вы работаете над этим, у вас есть проблема с временными объектами (такими как созданные SecondConcreteTpe()
) существуют только до конца выражения, поэтому указатель внутри FirstDecoratorType
будет недействительным, прежде чем вы сможете сделать что-нибудь полезное с ним.
Вы можете решить эту проблему, используя умные указатели для удержания декорированного типа в декораторе (например, std::unique_ptr
). Это делает декоратора ответственным за очистку декорированного шрифта.