я имею, записал шаблон "посетитель" следующим образом, но я не понимаю то, что является единственной и двойной отправкой. AFAIK, единственная отправка, вызывают метод на основе типа вызывающего абонента, где двойная отправка, вызывают метод на основе типа вызывающего абонента и типа аргумента.
Я предполагаю, что двойная отправка, происходят в иерархии единого класса, но почему класс посетителя имеет две иерархии классов, но это все еще рассмотрело как двойную отправку.
void floppyDisk::accept(equipmentVisitor* visitor)
{
visitor->visitFloppyDisk(this);
}
void processor::accept(equipmentVisitor* visitor)
{
visitor->visitProcessor(this);
}
void computer::accept(equipmentVisitor* visitor)
{
BOOST_FOREACH(equipment* anEquip, cont)
{
anEquip->accept(visitor);
}
visitor->visitComputer(this);
}
void visitFloppyDisk(floppyDisk* );
void visitProcessor(processor* );
void visitComputer(computer* );
Объясните использование примера кода, который я обеспечил.
AFAIK, первая отправка, происходят на объекте, кто вызывает принятие, и вторая отправка, происходят на объекте, кто вызывает метод посещения.
Спасибо.
Короче говоря, однократная отправка - это когда метод полиморфен по типу одного параметра (включая неявное this
). Двойная отправка - это полиморфизм по двум параметрам.
Типичным примером для первого является стандартный виртуальный метод, который полиморфен по типу содержащего объекта. А второй можно реализовать через паттерн Посетитель.
[update] Я предполагаю, что в вашем примере floppyDisk
, процессор
и компьютер
каждый наследует от общего базового класса, который определяет accept
как виртуальный метод. Точно так же методы visit *
должны быть объявлены виртуальными в equipmentVisitor
, у которого должны быть некоторые производные классы с различными реализациями visit *
. [/ update]
Исходя из вышесказанного, accept
полиморфен как на this
, так и на equipmentVisitor
. Дискета, процессор и компьютер имеют собственную реализацию accept
, поэтому, когда посетитель вызывает accept
, вызов отправляется в зависимости от типа вызываемого. Затем вызываемый вызывает метод посещения конкретного типа посетителя, и этот вызов отправляется на основе фактического типа посетителя.
Теоретически может быть тройная, учетверенная и т. Д. Диспетчеризация, хотя я никогда не видел, чтобы это реализовывалось на практике (на языках, которые не поддерживают двойную и более высокую диспетчеризацию по своей природе, то есть - я, кажется, помню, что Smalltalk делает ?).Двойная диспетчеризация с использованием Visitor в C ++ и подобных языках уже сама по себе ошеломляет, поэтому реализация тройной и более высокой диспетчеризации была бы слишком сложной для использования в реальных приложениях.
В вашем примере вам не хватает основ механизма: наследования и виртуальности. Предположим, что в дополнение к вашему коду используется следующая иерархия классов:
class equipmentVisited
{
virtual void accept(equipmentVisitor* visitor) = 0;
}
class floppyDisk : public equipmentVisited
{
virtual void accept(equipmentVisitor* visitor);
}
class processor : public equipmentVisited
{
virtual void accept(equipmentVisitor* visitor);
}
class computer : public equipmentVisited
{
virtual void accept(equipmentVisitor* visitor);
}
class equipmentVisitor
{
virtual void visitFloppyDisk(floppyDisk* );
virtual void visitProcessor(processor* );
virtual void visitComputer(computer* );
}
// Some additional classes inheriting from equipmentVisitor would be here
Теперь представьте, что у вас есть этот фрагмент кода в какой-то функции:
equipmentVisited* visited;
equipmentVisitor* visitor;
// ...
// Here you initialise visited and visitor in any convenient way
// ...
visited->accept(visitor);
Благодаря механизму двойной диспетчеризации эта последняя строка позволяет любому equipmentVisited
принимать любой equipmentVisitor
, независимо от их фактических статических типов. В конце концов, правильная функция будет вызвана для правильного класса.
Подведем итог:
accept()
для соответствующего класса