Переход от абстрактного интерфейса к конкретному классу
От: Michael Rusakov https://www.wincatalog.com
Дата: 26.06.07 03:00
Оценка:
Здравствуйте!

Имеется следующая программная структура. Ядро состоит из классов 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;
};
WinCatalog — Disk Catalog Software for Windows
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.