я прошел шаблон заводского дизайна и получил некоторые сомнения, код, который я видел, где в register
функции,
они сохраняют объект на map
(при регистрации, создании объектов в первый раз и хранении их в классе контейнера), когда нам нужен объект, который мы должны запрашивать у фабрики (Factory::getObject("Rectangle")
), это прямоугольник создается и сохраняется на карте уже во время регистрации, и этот объект возвращается, когда я getObject("Rectangle")
).
Я сомневаюсь, что каждый раз, когда я получаю только один объект, если я хочу создать 10 разных объектов для прямоугольника,
Как я могу создать 10 объектов diff этого прямоугольника?
Заранее спасибо.
RangeRingsFactory::RangeRingsFactory()
{
Register("Big", &Picture::Create); //picure & picyureInPicture inherited from IRangeRings
Register("Small", &PictureInPicture::Create);
}
RangeRingsFactory *RangeRingsFactory::Get()
{
static RangeRingsFactory instance;
return &instance;
}
void RangeRingsFactory::Register(const string &Name, CreateRRFn pfnCreate)
{
map1[Name] = pfnCreate;
}
IRangeRings *RangeRingsFactory::CreateRR(const string &Name)
{
FactoryMap::iterator it = map1.find(Name);
if( it != map1.end() )
return it->second();
return NULL;
}
картина:
Picture::Picture():IRangeRings()
{
setRangeScale(QRect(-200,-200,400,400));
}
IRangeRings *Picture::Create()
{
return new Picture();
}
главный:
MainWindow::MainWindow(QWidget *parent)
: QWidget(parent)
{
string Name1 = "Big";
IRangeRings *p1 = RangeRingsFactory::Get()->CreateRR(Name1);
string Name2 = "Small";
IRangeRings *p2 = RangeRingsFactory::Get()->CreateRR(Name2);
outerLayout = new QHBoxLayout;
outerLayout->addWidget(p1);
outerLayout->addWidget(p2);
this->setLayout(this->outerLayout);
}
Он будет иметь другой прямоугольник в IRangeRings, если вы установите другой прямоугольник при создании IRangeRings
.
Измените эти функции:
CreateRRFn()
IRangeRings *RangeRingsFactory::CreateRR(const string &Name)
IRangeRings *Picture::Create()
Для того, чтобы:
CreateRRFn(QRect rect)
IRangeRings *RangeRingsFactory::CreateRR(const string &Name, const QRect &rect)
IRangeRings *Picture::Create(const QRect &rect)
Затем используйте экземпляр RangeRingsFactory
для создания новых IRangeRings
следующим образом:
IRangeRings *p1 = RangeRingsFactory::Get()->CreateRR("Big", QRect(0, 0, 100, 100));
Также вы можете добавить новую чистую virtual
функцию в IRangeRings
(я думаю, что IRangeRings
- это класс интерфейса), я назвал его как ToSetRangeScale
. И Picture
и PictureInPicture
должны реализовать это:
void Picture::ToSetRangeScale(const QRect &rect) { setRangeScale(rect); }
void PictureInPicture::ToSetRangeScale(const QRect &rect) { setRangeScale(rect); }
Затем вызовите ToSetRangeScale
чтобы установить rect после создания объекта Picture
или PictureInPicture
:
IRangeRings *p1 = RangeRingsFactory::Get()->CreateRR("Big");
p1->ToSetRangeScale(QRect(0, 0, 100, 100));
В RangeRingsFactory
хранятся некоторые указатели функции Create
. Эта же функция может создать другой объект, который имеет тот же класс. Разная функция может создавать разные объекты с разными классами. Если вы хотите изменить свойство нового объекта, вы можете установить его свойство при создании объекта или после создания объекта новым методом.
На фабрике хранится карта строк для "функций создания". В его конструкторе он регистрирует два из них: "Большой" соответствует Picture::Create
и "Small" соответствует PictureInPicture::Create
.
Метод CreateRR
ищет данное Name
, вызывает соответствующую функцию создания и возвращает его результат.
Пока оба Picture::Create
и PictureInPicture::Create
производят новые объекты, вы получаете новый объект каждый раз, когда вы вызываете CreateRR
.
Так что на самом деле у вас есть...
две заводские функции - Picture::Create
и PictureInPicture::Create
- каждый из которых всегда создает один и тот же тип объекта
один заводский класс - RangeRingsFactory
- который скрывает от вас определенные типы (Picture
и PictureInPicture
), поэтому вы можете просто попросить один по имени ("Большой" или "Малый"), не зная и не заботясь о конкретном типе объекта, который создается.
Похоже, вы думаете о комбинации "прототипов" и "фабричных" моделей. Фабрика позволяет клиентам "регистрировать" экземпляры прототипов, которые могут быть подклассами некоторой общей базы. Затем метод getObject создает копию запрошенного прототипа.
Я сделал быстрый Google для "прототипа шаблона c++"... Вот два из многих результатов:
http://en.wikibooks.org/wiki/C%2B%2B_Programming/Code/Design_Patterns#Prototype
http://www.codeproject.com/Articles/185348/Prototype-Design-Pattern-2
Вот простой пример с использованием shape
базового класса и двух подклассов rectangle
и circle
. Эти классы мало что делают, но они имеют минимальную структуру для иллюстрации шаблона.
(Предупреждение: я на самом деле не компилировал это, так что дайте мне перерыв, если я сделаю простые ошибки!)
#include <map>
// Abstract base class for all shapes
class shape
{
public:
virtual ~shape() {}
virtual shape* clone() const = 0;
};
// Concrete subclass of shape
class rectangle : public shape
{
public:
virtual shape* clone() const override
{
return new rectangle( *this );
}
};
// Concrete subclass of shape
class circle : public shape
{
public:
virtual shape* clone() const override
{
return new circle( *this );
}
};
class Factory
{
public:
// Add the given prototype object to the factory
void register( std::string name, shape* proto )
{
protos[name] = proto;
}
// Get a copy of the prototype with the given name
shape* getObject( std::string const& name ) const
{
// Warning: This will throw if name is not found!
return protos[name]->clone();
}
private:
// Warning: This will leak unless cleaned up in the destructor!
std::map<std::string, shape*> protos;
};
int main()
{
Factory fact;
fact.register( "rectangle", new rectangle() );
fact.register( "circle", new circle() );
// These will be separate copies of the original prototype
shape* rect1 = fact.getObject( "rectangle" );
shape* rect2 = fact.getObject( "rectangle" );
// Don't leak!
delete rect1;
delete rect2;
}
Примечание. Я знаю, что есть много способов улучшить этот код, но я попытался сохранить его простым, чтобы избежать отвлечения внимания от ключевых моментов.
Factory::getObject
. Вы должны создать новый объект им. Можете ли вы добавить ссылку наfactory design pattern
который вы упомянули в квесте.