Здравствуйте!
Имеется следующая программная структура. Ядро состоит из классов CItem (1), CSaveItemToDb (2) и CVisitor (3). Клиент может работать с классами (1) и (2) через интерфейсы IItem и ISaver соответсвенно. Класс CVisitor является полностью недоступным для пользователя и находится исключительно в ядре.
Для сохранения элемента CItem в БД, необходимо создать экземпляр класса CVisitor, проинициализировать его должным образом и передать классу CItem. Дабы не нагружать класс Item дополнительным "знанием" о БД, вся функциональность связанная с БД вынесена в класс CSaveItemToDb.
Итак, хотелось бы, чтобы клиент мог выполнять примерно такой код:
IItem* pItem = //...
ISaver* pSaver = //...
pItem->setName(L"Вася");
pSaver->saveItem(pItem);
При этом проблема заключается в том, что функции ISaver::saveItem передается указатель на интерфейс, а посетителю требуется указатель на класс (см. код ниже). То есть необходимо понижающее приведение типа.
Сразу скажу, что передать классу-посетителю (CVisitor) указатель на интерфейс нельзя, т.к. тогда надо выводить посетителя на уровень интерфейсов (чтобы добавить функцию accept в интерфейс IItem), а значит раскрывать кучу подробностей реализации элемента в частности и ядра в целом. Да и вообще весь шаблон "Посетитель" тогда теряет смысл.
Сдается мне, что я в чем-то не прав. Только пока не могу понять в чем именно. Буду благодарен за любые подсказки.
Примерный код интерфейсов и ядра:
//уровень интерфейсов
interface IItem
{
virtual void setName(const wchar_t*) = 0;
virtual const wchar_t* getName() const = 0;
}
interface ISaver
{
virtual bool saveItem(IItem*) = 0;
}
//уровень ядра
class CItem : public IItem
{
public:
CItem(){}
virtual ~CItem(){}
virtual void setName(const wchar_t*) {/*...*/}
virtual const wchar_t* getName() const {/*...*/}
//Эта функция уровня ядра,
//она отсутствует в интерфейсе IItem
void acceptVisitor(CVisitor *v){v->visit(this);}
};
class CVisitor
{
//...
void visit(CItem*);
void setDatabase(CDb *pDb);
};
class CSaveItemToDb : public ISaver
{
public:
//....
virtual bool saveItem(IItem *pItem)
{
//Вот здесь нужно совершить переход
//от интерфейса к классу и выполнить
CVisitor v;
v->setDatabase(_pDb);
CItem *p = ??? pItem;
p->acceptVisitor(&v);
return true;
}
private:
CDb *_pDb;
};