visitante tiene una mala reputación, en parte debido a algunos problemas reales
- dependencia cíclica entre Vistor y jerarquías Visitado
- que se supone que arruinar la encapsulación mediante la exposición de las clases Visitado el funcionamiento interno
y en parte debido a la exposición en el libro de GOF, que enfatiza el recorrido de una estructura en lugar de agregar funciones virtuales a una jerarquía cerrada.
Esto significa que no se considera apropiado, por ejemplo, para resolver el problema del doble envío en lenguajes tipados estáticamente. Ejemplo: un mensaje o un sistema de paso de eventos en C++, donde los tipos de mensajes son fijos, pero queremos extenderlos agregando nuevos destinatarios. Aquí, los mensajes son solo estructuras, por lo que no nos importa encapsularlos. SendTo()
no sabe qué tipo de Message
o MessageRecipient
tiene.
#include <iostream>
#include <ostream>
using namespace std;
// Downside: note the cyclic dependencies, typically expressed in
// real life as include file dependency.
struct StartMessage;
struct StopMessage;
class MessageRecipient
{
public:
// Downside: hard to add new messages
virtual void handleMessage(const StartMessage& start) = 0;
virtual void handleMessage(const StopMessage& stop) = 0;
};
struct Message
{
virtual void dispatchTo(MessageRecipient& r) const = 0;
};
struct StartMessage : public Message
{
void dispatchTo(MessageRecipient& r) const
{
r.handleMessage(*this);
}
// public member data ...
};
struct StopMessage : public Message
{
StopMessage() {}
void dispatchTo(MessageRecipient& r) const
{
r.handleMessage(*this);
}
// public member data ...
};
// Upside: easy to add new recipient
class RobotArm : public MessageRecipient
{
public:
void handleMessage(const StopMessage& stop)
{
cout << "Robot arm stopped" << endl;
}
void handleMessage(const StartMessage& start)
{
cout << "Robot arm started" << endl;
}
};
class Conveyor : public MessageRecipient
{
public:
void handleMessage(const StopMessage& stop)
{
cout << "Conveyor stopped" << endl;
}
void handleMessage(const StartMessage& start)
{
cout << "Conveyor started" << endl;
}
};
void SendTo(const Message& m, MessageRecipient& r)
{
// magic double dispatch
m.dispatchTo(r);
}
int main()
{
Conveyor c;
RobotArm r;
SendTo(StartMessage(), c);
SendTo(StartMessage(), r);
SendTo(StopMessage(), r);
}