af
Зарегистрирован: 18.12.2007 Сообщения: 1
|
Добавлено: Вт Дек 18 2007 17:44 Заголовок сообщения: Паттерны 'абстрактная фабрика' и 'адаптер' |
|
|
Доброго времени суток.
Пишу проект, использующий стороннюю библиотеку (трёхмерный движок irrlicht). У неё очень громоздкий интерфейс, так что я хочу сделать обёртку, к которой можно было бы обращаться более лаконично.
По правилам хорошего тона не хочу привязываться к коннкретному движку, а сделать интерфейс любого движка для нужд своего проекта. То есть обёртка получается наследником абстрактного интерфейса.
Кроме того, возникает необходимость хранить в основной части программы некоторые данные, которые реализуются каждым движком по своему, например сферу.
Насколько я понимаю, для этого нужно заводить отдельный тип.
Ну и предполагается, что сама обёртка будет активно работать с данными таких типов (создавать, получать, обрабатывать).
Мне таки удалось написать компилирующийся код, но всё равно есть несколько вопросов
Код: |
// ===== engwrp.h =====
class TSphere
{
public:
virtual void display( float x, float y, float z, float size ) = 0;
};
class TEngineWrapper
{
public:
virtual ~TEngineWrapper();
virtual TSphere *obtainSphere( ) = 0;
virtual void arrangeSphere( TSphere *sphere, float x, float y, float z, float size ) = 0;
};
TEngineWrapper *createIrrlichtWrapper();
// ===== engwrp.cpp =====
#include "engwrp.h"
#include <irrlicht.h>
class TIrrlichtWrapper;
class TIrrlichtSphere : public TSphere
{
ISceneNode *node;
friend class TIrrlichtWrapper;
public:
TIrrlichtSphere( ISceneNode* _node );
virtual void display( float x, float y, float z, float size );
};
class TIrrlichtWrapper : public TEngineWrapper
{
IrrlichtDevice *device;
IVideoDriver *driver;
ISceneManager *sceneManager;
IGUIEnvironment *guiEnv;
public:
TIrrlichtWrapper();
virtual ~TIrrlichtWrapper();
virtual TSphere *obtainSphere();
virtual void arrangeSphere( TSphere *sphere, float x, float y, float z, float size );
};
TIrrlichtSphere::TIrrlichtSphere( ISceneNode *_node )
{
node = _node;
}
TIrrlichtWrapper::TIrrlichtWrapper()
{
device = createDevice( EDT_DIRECT3D9, dimension2d<s32>( 640, 480 ), 16 );
driver = device->getVideoDriver();
sceneManager = device->getSceneManager();
guiEnv = device->getGUIEnvironment();
}
TIrrlichtWrapper::~TIrrlichtWrapper()
{
device->drop();
}
TSphere *TIrrlichtWrapper::obtainSphere()
{
return new TIrrlichtSphere( sceneManager->addSphereSceneNode( ) );
}
void TIrrlichtWrapper::arrangeSphere( TSphere *sphere, float x, float y, float z, float size )
{
/*1*/
( ( TIrrlichtSphere* )appearence )->node->setPosition( vector3df( x, y, z ) );
( ( TIrrlichtSphere* )appearence )->node->setScale( vector3df( size, size, size ) );
}
TEngineWrapper *createIrrlichtWrapper()
{
return new TIrrlichtWrapper;
}
|
Теперь вопросы:
1) подскажите, как лучше сделать, разбить весь код на большое количество модулей (engwrp.h, engwrp.cpp, irrwrp.h, irrwrp.cpp (xors3d.h, xors3d.cpp, если буду впоследствии использовать движок xors3d) ) или оставить всё в двух файлах (engwrp.h и engwrp.cpp)?
2) в правильных ли местах описана и определена функция createIrrlicheWrapper?
3) самое главное про интерфейс TSphere и его реализацию TIrrlichtSphere. Как-то с ним полностью красиво не получается.
Например в /*1*/ приходится явно приводить тип к классу-наследнику, потому что, если описать функцию
Код: | void TIrrlichtWrapper::arrangeSphere( TIrrlichtSphere *sphere, float x, float y, float z, float size ); |
то компилятор не зачтёт эту функцию за реализацию чисто виртуальной
Код: | void TEngineWrapper::arrangeSphere( TSphere *sphere, float x, float y, float z, float size ); |
и не разрешит создать экземпляр абстрактного класса TIrrlichtWrapper.
Правильный ли вообще подход - описывать его отдельным от TEngineWrapper классом? Я пытался сделать TEngineWrapper шаблонным классом и передавать TSphere в качестве параметра, но при таком подходе явное обращение к TIrrlichtSphere вылазило в основную программу. |
|
tellary
Зарегистрирован: 29.01.2008 Сообщения: 7
|
Добавлено: Вт Янв 29 2008 11:22 Заголовок сообщения: |
|
|
1) Лучше: отдельные файлы на каждый новую имплементацию.
2) createIrrlecheWrapper не нужна вообще (либо должна быть объявлена в irrwrp.h), т.к. использование TEngineWrapper (и всего что с ним связно) будет идти в два шага:
а) создание конкретной имплементации
б) передача указателя TEngineWrapper* коду, который его будет использовать.
Код, из п. (б) будет знать только об интерфейсе, код из п. (а) будет знать о конкретной имплементации, которую создает, а посему может создать конкретный "энджин" оператором new, либо воспользоваться create-функцией объявленной в irrwrp.h. Если же оставить этот метод в engwrp.h, то для каждой новой имплементации придется модифицировать этот хедер.
3) Не понятно почему arrangeSpehere это метод движка, а не самой сферы. Если бы это был метод сферы, то проблемы с кастом не было бы, т.к. конкретный экземпляр сферы при вызове arrange знал бы к какой библиотеке обращаться (irrlicht или другая).
Если же оставить все как есть, то в принципе каст - это приемлемо.
"пытался сделать TEngineWrapper шаблонным классом и передавать TSphere в качестве параметра, но при таком подходе явное обращение к TIrrlichtSphere вылазило в основную программу." - как вариант: сделать клиентский код тоже шаблонным.
И немножко о вкусном:
1. В данном случае TEngineWrapper это не адаптер, а фасад.
2. Нужно подумать зачем вообще методы манипуляции со сверой оказались в фасаде движка, а не в самой сфере? Следуя этой идеологии можно и метод display вынести в "движок", а вместо TSphere-указателя в вызове obtainSpehere возвращать int в качестве handler'a на конкретную сферу. Может не стоит смешивать эти два подхода? |
|