Visitor ma złą reputację, częściowo z powodu pewnych realnych problemów
- cykliczną zależność między Vistor i odwiedził hierarchii
- to miało zniszczyć hermetyzacji wystawiając Odwiedzone klas wewnętrzne
i częściowo ze względu na ekspozycję w książce GOF, która kładzie nacisk na przechodzenie przez strukturę, zamiast dodawać funkcje wirtualne do zamkniętej hierarchii.
Oznacza to, że nie jest brane pod uwagę w razie potrzeby, np. W celu rozwiązania problemu podwójnej wysyłki w językach statycznie napisanych. Przykład: system przekazywania komunikatów lub zdarzeń w C++, w którym typy wiadomości są stałe, ale chcemy rozszerzyć, dodając nowych odbiorców. W tym przypadku wiadomości są po prostu strukturami, więc nie zależy nam na ich enkapsulacji. SendTo()
nie wie, jaki typ ma Message
lub MessageRecipient
.
#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);
}