Russian Qt Forum
Ноябрь 23, 2024, 12:05 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: [Решено]Абстрактная фабрика на шаблонах без STL!  (Прочитано 4957 раз)
kuzulis
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2812


Просмотр профиля
« : Сентябрь 28, 2013, 20:42 »

Доброго всем времени.

Я не очень вник в шаблонную магию, пересмотрел много ссылок и инфы в гугле, но конкретного решения на свой вопрос не нашел.

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

Без шаблонов я выполнил бы эту задачу как-то так:

Код
C++ (Qt)
enum ObjectType { PcmObjectType, Ac3ObjectType };
enum Direction { InputDirection, OutputDirection };
 
class Object
{
public:
   virtual void print() = 0;
}
 
// PCM objects
 
class PcmObject : public Object
{
public:
   PcmObject() { /* init a common PCM features */ }
}
 
class PcmInputObject : public PcmObject
{
public:
   PcmInputObject() { /* init a specific PCM Input features */ }
   void print() { /* I am PcmInputObject */}
}
 
class PcmOutputObject : public PcmObject
{
public:
   PcmOutputObject() { /* init a specific PCM Output features */ }
   void print() { /* I am PcmOutputObject */}
}
 
// AC3 objects
 
class Ac3Object : public Object
{
public:
   Ac3Object() { /* init a common AC3 features */ }
}
 
class Ac3InputObject : public Ac3Object
{
public:
   Ac3InputObject() { /* init a specific AC3 Input features */ }
   void print() { /* I am PcmInputObject */}
}
 
class Ac3OutputObject : public Ac3Object
{
public:
   Ac3OutputObject() { /* init a specific AC3 Output features */ }
   void print() { /* I am Ac3OutputObject */}
}
 
// factories
 
class AbstractFactory
{
public:
   virtual Object *create(Direction dir) = 0;
}
 
class PcmFactory : public AbstractFactory
{
public:
   Object *create(Direction dir) {
       switch (dir) {
       case InputDirection: return new PcmInputObject;
       case OutputDirection: return new PcmOutputObject;
       default: return 0;
       }
   }
}
 
class Ac3Factory : public AbstractFactory
{
public:
   Object *create(Direction dir) {
       switch (dir) {
       case InputDirection: return new Ac3nputObject;
       case OutputDirection: return new Ac3OutputObject;
       default: return 0;
       }
   }
}
 
// factory creator
 
class FactoryCreator
{
public:
   AbstractFactory *create(ObjectType objectType) {
       switch (objectType) {
       case PcmObjectType: return new PcmFactory;
       case Ac3ObjectType: return new Ac3Factory;
       default: return 0;
       }
   }
}
 
// usage
 
void main()
{
   // received the some initial properties from an some data source
   ObjectType objectType = PcmObjectType;
   Direction direction = OutputDirection;
 
   // need create a desired object from a properties
   FactoryCreator fc;
   AbstractFactory *factory = fc.create(objectType);
   Object *obj = factory->create(direction);
   obj->print();
 
   return 0;
}
 

Меня смущают лишние действия в виде switch/case, возможно ли что-то подобное сделать на шаблонах, но без switch/case?
« Последнее редактирование: Сентябрь 29, 2013, 15:05 от kuzulis » Записан

ArchLinux x86_64 / Win10 64 bit
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4350



Просмотр профиля
« Ответ #1 : Сентябрь 28, 2013, 22:29 »

возможно ли что-то подобное сделать на шаблонах, но без switch/case?
Возможно. Я вроде уже приводил код этой фабрики. Это вариант для C++11 с переменным числом параметров, которые можно передать в конструктор объекта при его создании. Если новый стандарт не нужен, от этого легко избавиться.
Сама фабрика и пример использования.
Код
C++ (Qt)
#include <memory>
#include <stdexcept>
#include <map>
 
// key - тип ключа для идентификации класса
// base - базовый класс для всех классов которые может создать фабрика
// params - список параметров, передающихся в конструктор
template <typename key, typename base, typename... params>
class factory
{
public:
   typedef std::shared_ptr<base> base_ptr;
 
   template <class derived>
   void reg( const key &name )
   {
       factories[ name ] = base_type_ptr( new derived_type<derived> );
   }
 
   base_ptr create( const key& name, params... p )
   {
       if( !factories.count( name ) )
           throw std::out_of_range( "factory: key not found" );
       return factories[ name ]->create( p... );
   }
 
private:
 
   class base_type
   {
   public:
 
       virtual ~base_type() {}
 
       virtual base_ptr create( params... ) const = 0;
   };
 
   typedef std::shared_ptr<base_type> base_type_ptr;
 
   template <class T>
   class derived_type : public base_type
   {
   public:
 
       virtual base_ptr create( params... p ) const
       {
           return base_ptr( new T( p... ) );
       }
   };
 
   typedef std::map<key, base_type_ptr> factory_container;
   factory_container factories;
};
 
// ===============================================================
#include <iostream>
 
class Figure
{
public:
   virtual    bool show() = 0;
};
 
class Elipse : public Figure
{
public:
   Elipse( int id, const std::string &param )
   {
       std::cout << "Build Elipce( " << param << " ) id = " << id << std::endl;
   }
 
   virtual    bool show() {}
};
 
class Square : public Figure
{
public:
   Square( int id, const std::string &param )
   {
       std::cout << "Build Square( " << param << " ) id = " << id << std::endl;
   }
 
   virtual    bool show() {}
};
 
int main( int, char ** )
{
   typedef factory<std::string, Figure, int, std::string> FigureFactory;
   typedef FigureFactory::base_ptr FigurePtr;
 
   FigureFactory figures;
 
   // Регистрируем фигуры
   figures.reg<Elipse>( "elipse" );
   figures.reg<Square>( "square" );
 
   FigurePtr fig;
 
   fig = figures.create( "square", 25, "x=45 y=87" );
 
   fig = figures.create( "elipse", 45, "x=10 y=30 radius=100" );
}
 
« Последнее редактирование: Сентябрь 28, 2013, 22:32 от Old » Записан
kuzulis
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2812


Просмотр профиля
« Ответ #2 : Сентябрь 29, 2013, 10:16 »

Ага, спасибо.

Но я вижу, что все-равно используется некоторый контейнер (вместо switch/case).

Но в моем случае применение любых STL сущностей неприемлемо ( я пишу драйвер для Windows, забыл об этом упомянуть, сорри ).

Поэтому, можно ли реализовать эту фабрику вообще без использования STL но на шаблонах?  Показает язык
« Последнее редактирование: Сентябрь 29, 2013, 10:21 от kuzulis » Записан

ArchLinux x86_64 / Win10 64 bit
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4350



Просмотр профиля
« Ответ #3 : Сентябрь 29, 2013, 10:30 »

Поэтому, можно ли реализовать эту фабрику вообще без использования STL но на шаблонах?  Показает язык
Реализовать свой контейнен. Вектор же хотя бы есть? Улыбающийся
Записан
kuzulis
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2812


Просмотр профиля
« Ответ #4 : Сентябрь 29, 2013, 11:24 »

Нету. Но есть "doubly linked list" - но оно чисто Си-шное...

Блин, даже не знаю, "стоит ли очинка выделки?" (С)

UPD: Я так понимаю, что без контейнеров не обойтись? Так? Тогда это по-сути ничем не отличается от switch/case, т.к. все-равно происходит выборка по ключу... Или я ошибаюсь?
« Последнее редактирование: Сентябрь 29, 2013, 11:28 от kuzulis » Записан

ArchLinux x86_64 / Win10 64 bit
Akon
Гость
« Ответ #5 : Сентябрь 29, 2013, 12:04 »

Перед использованием в рантайме какой-либо фабрики мы имеем уже созданные экземпляры этих фабрик. Контейнер связывает ключ с экземпляром фабрики. Какой контейнер - не суть. Например, мы можем иметь два массив: массив строк, используемых как ключи, и массив адресов фабрик. По ключу находим его индекс, по индексу - адрес. switch/case в сравнении со списком просто жестко зашитая в код конструкция, и у пользователя (программист, использующего ваш код) нет возможности добавлять новые фабрики.
Записан
kuzulis
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2812


Просмотр профиля
« Ответ #6 : Сентябрь 29, 2013, 15:05 »

Ok, спасибо за разъяснения.
Записан

ArchLinux x86_64 / Win10 64 bit
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.188 секунд. Запросов: 23.