Attualmente sto lavorando a un progetto in cui ho bisogno di manipolare una struttura dati ad albero, che ho implementato con un modello composito. Voglio essere in grado di fare diverse azioni su questa struttura dati, quindi ho implementato un modello di visitatore.
Stavo iniziando a vedere alcuni duplicati di codice tra i miei visitatori, quindi ho deciso di implementare un modello di decoratore sui miei visitatori. I decoratori implementano l'interfaccia Visitor e il loro costruttore accetta un visitatore come parametro.
L'idea è che il decoratore esegua del codice prima, esegue il suo visitatore di base (quello passato come parametro) ed esegue un codice dopo, un po 'così:
class ConcreteDecorator {
decoratedVisitor: Visitor
visitLeaf(leaf) {
// Do some stuff before
result := decoratedVisitor.visitLeaf(leaf)
// Do some stuff after
return result;
}
visitComposite(composite) {
// Do some stuff before
result := decoratedVisitor.visitComposite(leaf)
// Do some stuff after
return result;
}
}
Il decoratore / materiale per i visitatori può essere configurato in questo modo:
visitor := new ConcreteVisitorA()
visitor := new ConcreteDecoratorA(visitor)
Visitor := new ConcreteDecoratorB(visitor)
Il problema è che, una volta che chiamo visitComposite su un decoratore, ad esempio, il decoratore fa la sua roba, quindi chiama la sua visita visitatoreComposite. Poiché visitComposite è un metodo ricorsivo, quando viene chiamato su ConcreteVisitor e il metodo fa le sue chiamate ricorsive, perdiamo i decoratori. I decoratori vengono applicati solo al primo nodo visitato.
Ho pensato a soluzioni diverse, come l'utilizzo dell'ereditarietà invece dei decoratori, ma voglio poter riutilizzare i decoratori su visitatori diversi, quindi non è un'opzione praticabile.
Ho anche pensato di usare un qualche tipo di schema di strategia. Le strategie avrebbero un metodo beforeVisitLeaf / afterVisitLeaf e beforeVisitComposite / afterVisitComposite. Il problema è che non posso implementare un decoratore di filtri, che interrompa la visita di determinati nodi.
Sono riuscito a fare una hack questa soluzione e farlo funzionare mantenendo un aggancio sui metodi dei visitatori secondari e sostituendo manualmente i metodi dell'istanza del visitatore secondario con i metodi decorator (posso farlo perché ... JavaScript).
Questa soluzione è super hacky, quindi mi chiedevo se avessi qualche idea di progettazione su come risolvere il problema.