Название: [Решено]Абстрактная фабрика на шаблонах без STL!
Отправлено: kuzulis от Сентябрь 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?
Название: Re: Абстрактная фабрика на шаблонах
Отправлено: Old от Сентябрь 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 ¶m ) { std::cout << "Build Elipce( " << param << " ) id = " << id << std::endl; } virtual bool show() {} }; class Square : public Figure { public: Square( int id, const std::string ¶m ) { 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" ); }
Название: Re: Абстрактная фабрика на шаблонах без STL!
Отправлено: kuzulis от Сентябрь 29, 2013, 10:16
Ага, спасибо.
Но я вижу, что все-равно используется некоторый контейнер (вместо switch/case).
Но в моем случае применение любых STL сущностей неприемлемо ( я пишу драйвер для Windows, забыл об этом упомянуть, сорри ).
Поэтому, можно ли реализовать эту фабрику вообще без использования STL но на шаблонах? :P
Название: Re: Абстрактная фабрика на шаблонах без STL!
Отправлено: Old от Сентябрь 29, 2013, 10:30
Поэтому, можно ли реализовать эту фабрику вообще без использования STL но на шаблонах? :P
Реализовать свой контейнен. Вектор же хотя бы есть? :)
Название: Re: Абстрактная фабрика на шаблонах без STL!
Отправлено: kuzulis от Сентябрь 29, 2013, 11:24
Нету. Но есть "doubly linked list" - но оно чисто Си-шное...
Блин, даже не знаю, "стоит ли очинка выделки?" (С)
UPD: Я так понимаю, что без контейнеров не обойтись? Так? Тогда это по-сути ничем не отличается от switch/case, т.к. все-равно происходит выборка по ключу... Или я ошибаюсь?
Название: Re: Абстрактная фабрика на шаблонах без STL!
Отправлено: Akon от Сентябрь 29, 2013, 12:04
Перед использованием в рантайме какой-либо фабрики мы имеем уже созданные экземпляры этих фабрик. Контейнер связывает ключ с экземпляром фабрики. Какой контейнер - не суть. Например, мы можем иметь два массив: массив строк, используемых как ключи, и массив адресов фабрик. По ключу находим его индекс, по индексу - адрес. switch/case в сравнении со списком просто жестко зашитая в код конструкция, и у пользователя (программист, использующего ваш код) нет возможности добавлять новые фабрики.
Название: [Решено]Re: Абстрактная фабрика на шаблонах без STL!
Отправлено: kuzulis от Сентябрь 29, 2013, 15:05
Ok, спасибо за разъяснения.
|