Без рубрики

Qt шаблон проектирования Абстрактная фабрика (Abstract factory)

Абстрактная фабрика —  порождающий шаблон проектирования, позволяющий изменять поведение системы, варьируя создаваемыми объектами, при этом сохраняя интерфейсы. Он позволяет создавать целые группы взаимосвязанных объектов, которые, будучи созданными одной фабрикой, реализуют общее поведение. Шаблон реализуется созданием абстрактного класса Factory, который представляет собой интерфейс для создания компонентов системы (например, для оконного интерфейса он может создавать окна и кнопки). Затем пишутся наследники от него классы, реализующие этот интерфейс.

Сам код:

#ifndef FACTORY_H
#define FACTORY_H

#include <QString>
#include <QHash>
#include <QMap>

#include <QDebug>

template <class Base>
class AbstractCreator
{
public:
    AbstractCreator() {}
    virtual ~AbstractCreator(){}
    virtual Base* create()= 0;
    Base * instance=0;
};

template <class C, class Base>
class Creator : public AbstractCreator<Base>
{
public:
    Creator() { }
    virtual ~Creator()	{}
    Base * create() { this->instance= new C(); return this->instance; }

};

template <class Base, class IdType>
class Factory
{
protected:
    typedef AbstractCreator<Base> AbstractFactory;
    typedef std::map<IdType, AbstractFactory*> FactoryMap;

public:
    Factory() {}
    virtual ~Factory() {}
    template <class C>
    void add(const IdType & id) {
        registerClass(id, new Creator<C, Base>());
    }
    Base * create(const IdType & id) const {
        typename FactoryMap::const_iterator it = _factory.find(id);
        if (it != _factory.end())
            return it->second->create();
    }
    Base * getInstance(const IdType & id) const {
        typename FactoryMap::const_iterator it = _factory.find(id);
        if (it != _factory.end()) {
            if (it->second->instance!=0) return it->second->instance;
            return it->second->create();
        }
    }
protected:
    void registerClass(const IdType & id, AbstractFactory * p) {
        typename FactoryMap::iterator it = _factory.find(id);
        if (it == _factory.end())
            _factory[id] = p;
        else
            delete p;
    }
private:
    Factory(const Factory&);
    Factory& operator = (const Factory&);
    FactoryMap	_factory;
};

#endif // FACTORY_H

 

Теперь применение:
Где-нибудь в заголовочном файле:


class BaseCL {// базовый класс
public:
    virtual ~BaseCL() {}
};

class Foo : public BaseCL  // производные
{
public:
    int i=0;
    void msg() { qDebug()<<"Foo";   }
};

typedef Factory<BaseCL, QString> TypeFactory;  // Фабрика с базовым классом BaseCL и идентификаторами типа QString

Применение:

TypeFactory myfactory;
myfactory.add<Foo>("FOO"); //-- добавляем класс в фабрику

Foo *p = dynamic_cast<Foo *>(myfactory.create("FOO")); //-- создаем класс по идентификатору и приводим к типу Foo
p->msg(); //-- вызываем функцию вывода сообщения

1 comment

Dostoevskyi 17 мая 2019 - 10:35
Base * create(const IdType & id) const: Base * getInstance(const IdType & id) const: warning: control reaches end of non-void function [-Wreturn-type] }
Add Comment