Quello di cui gli stessi autori di Design Patterns si preoccupavano maggiormente era il pattern "Visitor".
È un "male necessario", ma viene spesso utilizzato in modo eccessivo e la necessità di esso spesso rivela un difetto più fondamentale nel tuo design.
Un nome alternativo per il pattern "Visitor" è "Multi-dispatch", perché il pattern Visitor è ciò che si ottiene quando si desidera utilizzare un linguaggio OO di invio di un solo tipo per selezionare il codice da utilizzare in base al tipo di due (o più) oggetti diversi.
L'esempio classico è che hai l'intersezione tra due forme, ma c'è un caso ancora più semplice che spesso viene trascurato: confrontare l'uguaglianza di due oggetti eterogenei.
Ad ogni modo, spesso ti ritrovi con qualcosa del genere:
interface IShape
{
double intersectWith(Triangle t);
double intersectWith(Rectangle r);
double intersectWith(Circle c);
}
Il problema con questo è che hai accoppiato tutte le tue implementazioni di "IShape". Hai insinuato che ogni volta che desideri aggiungere una nuova forma alla gerarchia dovrai cambiare anche tutte le altre implementazioni "Forma".
A volte, questo è il design minimale corretto, ma pensaci bene. Il tuo progetto richiede davvero che tu debba spedire su due tipi? Sei disposto a scrivere ciascuna delle esplosioni combinatorie dei multi-metodi?
Spesso, introducendo un altro concetto puoi ridurre il numero di combinazioni che dovrai effettivamente scrivere:
interface IShape
{
Area getArea();
}
class Area
{
public double intersectWith(Area otherArea);
...
}
Certo, dipende - a volte è davvero necessario scrivere codice per gestire tutti questi casi diversi - ma vale la pena fare una pausa e riflettere prima di fare il grande passo e utilizzare Visitor. Potrebbe farti risparmiare molto dolore in seguito.