Contesto
Ho usato con una gerarchia di oggetti (un albero di espressioni) un pattern di visitatore "pseudo" (pseudo, in quanto non usa la doppia distribuzione):
public interface MyInterface
{
void Accept(SomeClass operationClass);
}
public class MyImpl : MyInterface
{
public void Accept(SomeClass operationClass)
{
operationClass.DoSomething();
operationClass.DoSomethingElse();
// ... and so on ...
}
}
Questo design è stato, tuttavia, discutibile, piuttosto constrongvole poiché il numero di implementazioni di MyInterface è significativo (circa 50 o più) e non ho bisogno di aggiungere operazioni aggiuntive.
Ogni implementazione è unica (è un'espressione o operatore diverso) e alcuni sono compositi (cioè nodi dell'operatore che conterranno altri nodi operatore / foglia).
L'attraversamento viene attualmente eseguito chiamando l'operazione Accept sul nodo radice dell'albero, che a sua volta chiama Accept su ciascuno dei suoi nodi figli, che a sua volta ... e così via ...
Ma è giunto il momento in cui ho bisogno di aggiungere una nuova operazione , ad esempio una bella stampa:
public class MyImpl : MyInterface
{
// Property does not come from MyInterface
public string SomeProperty { get; set; }
public void Accept(SomeClass operationClass)
{
operationClass.DoSomething();
operationClass.DoSomethingElse();
// ... and so on ...
}
public void Accept(SomePrettyPrinter printer)
{
printer.PrettyPrint(this.SomeProperty);
}
}
In pratica vedo due opzioni:
- Mantieni lo stesso design, aggiungendo un nuovo metodo per la mia operazione a ogni classe derivata, a scapito della manutenibilità (non un'opzione, IMHO)
- Utilizza il pattern "true" Visitor, a scapito dell'estensibilità (non un'opzione, poiché mi aspetto di avere più implementazioni lungo la strada ...), con circa 50+ overload del metodo Visit, ognuno corrispondente un'implementazione specifica?
Domanda
Consiglieresti di utilizzare il pattern Visitor? C'è qualche altro modello che potrebbe aiutare a risolvere questo problema?