Вопрос по паттерну Фабрика
От: anidal  
Дата: 26.04.08 10:12
Оценка:
Вопрос к Гуру.
Есть проект на С, достаточно объёмный, в к-м реализован (естественно на C)
аналог паттерна фабрика.
Сейчас, в связи со значительный расширением функционала возникла идея перевести код на С++,
благо архитектура очень хорошо подходит под ООП и аналог ООП на С уже реализован.
Однако есть вопрос:
Основа системы — механизм создания/удаления экземпляров разл. классов.
Есть файл, в к-м описывается, сколько, каких, в каком порядке и с какими параметрами надо создать экземпляров классов.

//заголовочник
typedef struct _UNI_FACE{
    long Id;
    _UNI_FACE* (*Constructor) (CCModule* pCCModule);
    void (*Destructor)       (_UNI_FACE* This);
} UNI_FACE;



    unsigned long Id = pCCModule->ulModuleId;
    long i;
    long size=0;
    UNI_FACE* current = NULL;                     

    #pragma segment="CID_INIT_SEGMENT"
    UNI_FACE **pointer = (UNI_FACE**)__segment_begin("CID_INIT_SEGMENT");
    #pragma segment="CID_INIT_SEGMENT"
    size=__segment_size("CID_INIT_SEGMENT");
    size /= sizeof(UNI_FACE *); //4;                                    
    for (i = 0; i < size; i++) {                    
        if (pointer[i]->Id == Id) {
            current = pointer[i];
            break;
        }
    }
    if (!current) {                             
        return NULL;
    }
    current = (UNI_FACE *)current->Constructor(pCCModule); 
    if (!current) {                              
        return NULL;
    }
    LInsert(&configuration_head,current);

pCCModule — данные о классе и его парамерах
CID_INIT_SEGMENT — сегмент, в к-м храняться данные о имеющихся в системе типах классов.
Для каждого класса есть константная структура, указатель на к-ю и кладётся в сегмент CID_INIT_SEGMENT

UNI_FACE* ID10000_Constructor (CCModule* pCCModule);
void  ID10000_Destructor  (UNI_FACE* This);


const UNI_FACE ID10000_face={
    ID10000,
    ID10000_Constructor,
    ID10000_Destructor
};


#pragma location="CID_INIT_SEGMENT"                    
__root void* const ID10000Point=(void*)&ID10000_face;


путем добавления/исключения соотв. .с файлов можно добавлять и удалять типы классов в системе.


Теперь проблема — рассмотрел реализации такого механизма на С++. Предлагается либо в реализации фабрики заранее задавать
switch с прямыми вызовами конструкторов соотв. классов, либо иметь массив (Id,*класс), в к-м регистрировать имеющиеся классы.
Оба подхода неприемлемы, т.к. требуют при изменении состава классов менять код фабрики (или её инициализации). Существует ли иной путь?
Re: Вопрос по паттерну Фабрика
От: Sni4ok  
Дата: 26.04.08 10:44
Оценка: -1
Здравствуйте, anidal

есть код, работыает — нареканий нет-
а вот вам игла впилась в одно место- и нужно ресурсы потратить, потому и переписываете?
Re: Вопрос по паттерну Фабрика
От: Erop Россия  
Дата: 26.04.08 10:46
Оценка: 2 (1)
Здравствуйте, anidal, Вы писали:

A>Оба подхода неприемлемы, т.к. требуют при изменении состава классов менять код фабрики (или её инициализации). Существует ли иной путь?


Да, заводишь шаблонный класс примерно такой:
template<typename T>
class ClassRegistrar {
public:
    ClassRegistrar( const std::string& classTextId )
    {
        ::RegisterCreateFunction( classTextId, &createFunction );
    }
private:
    static T* createFunction() { return new T; }
};


Ну и регишь все классы в системе в месте их описания, создавая соотетствующий статический объект.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[2]: Вопрос по паттерну Фабрика
От: anidal  
Дата: 26.04.08 13:56
Оценка:
->Sni4ok:

А существующую систему менять и не собираюсь, а на сл. прибор сл. соображения:
1. Отсутствие наследования на С ->оверхед по коду, от 20 до 40 %. — а это уже экономия ценного ресурса — Flash.
2. Надоело писать велосипеды типа списков, деревьев и пр.
3. Квалификацию повышать надо? А за счёт работодателя и приятно и полезно

P.S. Embeded C++ генерит весьма эффективный код, на С иногда так не напишешь, только на ассемблере.



Здравствуйте, Erop, Вы писали:

E>Здравствуйте, anidal, Вы писали:


A>>Оба подхода неприемлемы, т.к. требуют при изменении состава классов менять код фабрики (или её инициализации). Существует ли иной путь?


E>Да, заводишь шаблонный класс примерно такой:
template<typename T>
E>class ClassRegistrar {
E>public:
E>    ClassRegistrar( const std::string& classTextId )
E>    {
E>        ::RegisterCreateFunction( classTextId, &createFunction );
E>    }
E>private:
E>    static T* createFunction() { return new T; }
E>};


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


Понял, спасибо.
Re[3]: Вопрос по паттерну Фабрика
От: Erop Россия  
Дата: 26.04.08 14:22
Оценка: 1 (1) +1 -1
Здравствуйте, anidal, Вы писали:

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

A>Понял, спасибо.

Для "спасибо" тут есть кнопки

Ты главное, это, пока не накопишь опыта разработки под С++ с шаблонами поаккуратнее. Не пиши их много, а то у новичков в С++ часто бывают с этим проблемы, AFAIK.

Удачи.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re: Вопрос по паттерну Фабрика
От: remark Россия http://www.1024cores.net/
Дата: 26.04.08 15:23
Оценка:
Здравствуйте, anidal, Вы писали:

A>Теперь проблема — рассмотрел реализации такого механизма на С++. Предлагается либо в реализации фабрики заранее задавать

A>switch с прямыми вызовами конструкторов соотв. классов, либо иметь массив (Id,*класс), в к-м регистрировать имеющиеся классы.
A>Оба подхода неприемлемы, т.к. требуют при изменении состава классов менять код фабрики (или её инициализации). Существует ли иной путь?


http://gzip.rsdn.ru/forum/message/1788774.1.aspx
Автор: remark
Дата: 17.03.06




1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[2]: Вопрос по паттерну Фабрика
От: Erop Россия  
Дата: 26.04.08 17:08
Оценка: 1 (1)
Здравствуйте, remark, Вы писали:

R>http://gzip.rsdn.ru/forum/message/1788774.1.aspx
Автор: remark
Дата: 17.03.06


IMHO, сложное очень решение
Вот смотри, один класс и в нём простой nested class template:
template< typename TInterface, typename TPtr = shared_ptr<TInterface> > class ObjectsFactory {
public:
    typedef std::string TypeId;
    typedef TPtr Ptr;

    static Ptr Create( const TypeId& id )
    {
        CreateFunction foo* = db()[id];
        assert( foo != 0 );
        return foo();
    }

    template<typename T> class Registrar {
    public:
        Registrar( const TypeId& id ) : id( id ) { reg( id, &creator ); }
        ~Registrar() { unreg( id ); }
    private:
        const TypeId id;
        Registrar( const Registrar& );
        void operator = ( const Registrar& );
        static Ptr creator() { return new T; }
    };
    
private:
    typedef Ptr CreateFunction();
    typedef std::map<TypeId, CreateFunction*> DB;
    static DB& db()
    {
        static DB creators;  // синглетон Маерса, так как Registrar -- статические объекты.
        return creators;
    }
    static void reg( const TypeId& id, CreateFunction* foo )
    {
        assert( foo != 0 && db()[id] == 0 );
        db()[id] = foo;
    }
    static void unreg( const TypeId& id )
    {
        assert( db()[id] != 0 );
        db()[id] = 0;
    }
};


Ну и теперь использование:
//  MyInterface.h
struct IMyInterface { virtual ~IMyInterface() {} };
typedef ObjectsFactory<IMyInterface> MyFactory;
const char* const MyInterfaceImpl1TypeId = "MySubsystem::MySubsubsystem::MyInterfaceImpl1";
const char* const MyInterfaceImpl2TypeId = "MySubsystem::MySubsubsystem::MyInterfaceImpl2";

//  MyInterfaceImpl1.h
class MyInterfaceImpl1 : public IMyImterface {
public:
    // тут реализация
};
// В MyInterfaceImpl1.cpp
static MyFactory::Registrar<MyInterfaceImpl1> impl( MyInterfaceImpl1TypeId );

//  MyInterfaceImpl2.h
class MyInterfaceImpl2 : public IMyImterface {
public:
    // тут реализация
};
// В MyInterfaceImpl2.cpp
static MyFactory::Registrar<MyInterfaceImpl2> impl( MyInterfaceImpl2TypeId );


IMHO радикально проще и прямее
И пользователям MyInterface, кстати, не надо знать о MyInterfaceImpl1.h, MyInterfaceImpl2.h и т. д...

Если таки хочется обязать пользователя иметь в классе-реализации статическое поле с TypeId, то можно приделать в ObjectFactory::Registrar() занчение параметра по умолчанию T::TypeId, например.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[2]: Вопрос по паттерну Фабрика
От: anidal  
Дата: 26.04.08 17:58
Оценка:
Здравствуйте, remark, Вы писали:

R>Здравствуйте, anidal, Вы писали:


A>>Теперь проблема — рассмотрел реализации такого механизма на С++. Предлагается либо в реализации фабрики заранее задавать

A>>switch с прямыми вызовами конструкторов соотв. классов, либо иметь массив (Id,*класс), в к-м регистрировать имеющиеся классы.
A>>Оба подхода неприемлемы, т.к. требуют при изменении состава классов менять код фабрики (или её инициализации). Существует ли иной путь?


R>http://gzip.rsdn.ru/forum/message/1788774.1.aspx
Автор: remark
Дата: 17.03.06



R>


К сожалению, это Embedded C++ — boost не подцепишь.
Re[3]: Вопрос по паттерну Фабрика
От: Erop Россия  
Дата: 26.04.08 18:45
Оценка:
Здравствуйте, anidal, Вы писали:

A>К сожалению, это Embedded C++ — boost не подцепишь.

Буст там не главное. Просто из буста он взял shared_ptr. Можно и не брать. В конце концов из фабрики можно и T* возвращать...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[3]: Вопрос по паттерну Фабрика
От: remark Россия http://www.1024cores.net/
Дата: 26.04.08 21:19
Оценка:
Здравствуйте, anidal, Вы писали:

A>Здравствуйте, remark, Вы писали:


R>>Здравствуйте, anidal, Вы писали:


A>>>Теперь проблема — рассмотрел реализации такого механизма на С++. Предлагается либо в реализации фабрики заранее задавать

A>>>switch с прямыми вызовами конструкторов соотв. классов, либо иметь массив (Id,*класс), в к-м регистрировать имеющиеся классы.
A>>>Оба подхода неприемлемы, т.к. требуют при изменении состава классов менять код фабрики (или её инициализации). Существует ли иной путь?


R>>http://gzip.rsdn.ru/forum/message/1788774.1.aspx
Автор: remark
Дата: 17.03.06



A>К сожалению, это Embedded C++ — boost не подцепишь.



Я вобщем-то не предлагаю boost подцеплять, я предлагаю схему решения.



1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[4]: Вопрос по паттерну Фабрика
От: anidal  
Дата: 27.04.08 04:05
Оценка:
Здравствуйте, remark, Вы писали:

R>Здравствуйте, anidal, Вы писали:


A>>Здравствуйте, remark, Вы писали:


R>>>Здравствуйте, anidal, Вы писали:


A>>>>Теперь проблема — рассмотрел реализации такого механизма на С++. Предлагается либо в реализации фабрики заранее задавать

A>>>>switch с прямыми вызовами конструкторов соотв. классов, либо иметь массив (Id,*класс), в к-м регистрировать имеющиеся классы.
A>>>>Оба подхода неприемлемы, т.к. требуют при изменении состава классов менять код фабрики (или её инициализации). Существует ли иной путь?


R>>>http://gzip.rsdn.ru/forum/message/1788774.1.aspx
Автор: remark
Дата: 17.03.06



A>>К сожалению, это Embedded C++ — boost не подцепишь.



R>Я вобщем-то не предлагаю boost подцеплять, я предлагаю схему решения.



R>

Схему понял, пошёл копать...
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.