Универсальный C Заводская++


Для моего проекта, мне нужен способ, чтобы инстанцировать различных типов объектов во время выполнения, используя "названия строк", для этого я разработал универсальный завод, который создается для каждого объекта типа иерархии (в настоящее время существуют два различных иерархий, которые нуждаются в заводе).

Мы хотим, чтобы завод, чтобы быть простым в использовании и простой для регистрации нового вида, для этого фабрика использует два вида классов.

Первый, является создателем объекта, что каждый новый класс, который должен зарегистрироваться на заводской экземпляр, это формируется как показано ниже:

template <typename T, typename Y>
class ObjectCreatorBase_c: public ObjectCreatorAutoUnlinkHook_t
{
    public:
        typedef T ObjectType_t;
        typedef Y ObjectCreatorProc_t;

     public:
        ObjectCreatorBase_c(const String_c &name, ObjectCreatorProc_t proc):
            strName(name),
            pfnCreateProc(proc)
        {
            if(proc == NULL)
            {
                std::stringstream stream;
                stream << "creator proc cant be null, entity " << name;
                PH_RAISE(INVALID_PARAMETER_EXCEPTION, "[ObjectCreatorBase_c::ObjectCreatorBase_c]", stream.str());
            }
        }

        T Create(const String_c &name) const
        {
            return pfnCreateProc(name);
        }

        inline const String_c &GetName() const
        {
            return strName;
        }

        inline bool operator<(const ObjectCreatorBase_c &rhs) const
        {
            return strName.compare(rhs.strName) < 0;
        }

    private:
        String_c strName;

    protected:
        ObjectCreatorProc_t pfnCreateProc;
};

Этот базовый класс создается, потому что есть два типа (прямо сейчас) функции создания, один с одним параметром для конструктора, а другая с двумя. Каждый тип специализирован, как показано ниже:

template <typename T>
class ObjectCreator_c: public ObjectCreatorBase_c<T, T(*)(const String_c &)>
{
    public:                     
        typedef ObjectCreatorBase_c<T, ObjectCreatorProc_t> BaseType_t;

    public:
        ObjectCreator_c(const String_c &name, ObjectCreatorProc_t proc):
            BaseType_t(name, proc)              
        {               
            GenericFactory_c<ObjectCreator_c<T> >::GetInstance().Register(*this);
        }
};

template <typename T, typename Y>
class ObjectCreator1_c: public ObjectCreatorBase_c<T, T(*)(const String_c &, Y )>
{       
    public:
        ObjectCreator1_c(const String_c &name,  T(*proc)(const String_c &, Y ) ):
            ObjectCreatorBase_c(name, proc)             
        {               
            GenericFactory1_c<ObjectCreator1_c, Y >::GetInstance().Register(*this);
        }

        T Create(const String_c &name, Y param) const
        {
            return pfnCreateProc(name, param);
        }
};

Первый создатель просто строковый параметр по умолчанию, который является общим для всех классов, а второй имеет дополнительный параметр шаблона, который можно настроить.

Наконец-то завода определяется как показано ниже:

template <typename T>
class GenericFactory_c: boost::noncopyable
{
    public:
        typedef typename T::ObjectType_t ObjectType_t;

        static GenericFactory_c &GetInstance()
        {
            static GenericFactory_c<T> clInstance_gl;

            return clInstance_gl;
        }

        ObjectType_t Create(const String_c &className, const String_c &name) const
        {
            return this->GetObjectCreator(className).Create(name);              
        }               

    protected:
        GenericFactory_c() { }

        friend T;           

        void Register(T &creator)
        {
            setObjectCreators.insert(creator);
        }

        const T &GetObjectCreator(const String_c &className) const
        {
            typename ObjectCreatorSet_t::const_iterator it = setObjectCreators.find(className, ObjectCreatorComp_s<T>());
            if(it == setObjectCreators.end())
                PH_RAISE(OBJECT_NOT_FOUND_EXCEPTION, "[EntityFactory_c::Create]", className);

            return *it;
        }

    protected:          
        typedef boost::intrusive::set<T, boost::intrusive::constant_time_size<false> > ObjectCreatorSet_t;
        ObjectCreatorSet_t setObjectCreators;
};

Кроме того, существует специализация завода на объект с дополнительным параметром:

template <typename T, typename Y>
class GenericFactory1_c: public GenericFactory_c<T>
{   
    public:
        static GenericFactory1_c &GetInstance()
        {
            static GenericFactory1_c clInstance_gl;

            return clInstance_gl;
        }

        ObjectType_t Create(const String_c &className, const String_c &name, Y param) const
        {
            return this->GetObjectCreator(className).Create(name, param);
        }
};

По последним, я создал это "сопоставимо" объект для поиска набор создателей:

    template<typename T>
    struct ObjectCreatorComp_s
    {
        bool operator()(const String_c &name, const T &res) const
        {
            return name.compare(res.GetName()) < 0;
        }

        bool operator()(const T &res, const String_c &name) const
        {
            return res.GetName().compare(name) < 0;
        }
    };

Чтобы помочь понять код, приведенный выше, ниже я покажу, как он используется. Например, для определения нового типа, которые будут использоваться с фабрики, мы используем:

typedef GenericFactory<ObjectCreator_c<MyObject*> > MyObjectFactory_t;

Определите объект Творца для конкретного типа:

static ObjectCreator<MyObject*> MyConcreteObject_CreatorObject("MyConcreteObject", MyConcreateObject::Create);

Где мы предполагаем, что "MyConcreteObject" имеет статический метод, называемый "создать", которая возвращает новый экземпляр типа.

Отметим также, что создатель экземпляра автоматически регистрируется на соответствующую фабрику.

Для того, чтобы создать экземпляр объекта, мы можем использовать:

MyObject *obj = MyObjectFactory_t::GetInstance().Create("MyConcreteObject", "objectName");

Любой мысли или предложения по поводу дизайна или простые способы сделать это, добро пожаловать!

Спасибо



Комментарии
1 ответ

Вот две вещи, которые вы могли бы сделать, чтобы обобщить картину завода и отвязать проблема параметра. Или как бы сделать вашу жизнь проще.


  1. Вы могли бы рассмотреть с помощью понятия импульс::любой разрешить произвольное число аргументов любого типа в конструкторе списка.

  2. Пишите в концепции нулевого типа (пустой класс), чтобы представить случай, когда параметризации типа Y-это пустое.

  3. Классы черты характера позволяют иерархий носителей сделать выбор поведения на основе типа.

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

PS: Я не фанат этого класса типа именования стиль ObjectType_t. Имя типа-это двойная тавтология.

3
ответ дан 10 сентября 2011 в 06:09 Источник Поделиться