Sto utilizzando un modello composito con più classi di nodi foglia che dispongono di operazioni specialistiche e di un modello di visitatore per consentire l'esecuzione di tali operazioni. In questo esempio ho omesso tutti i metodi ovvi accept
per chiarezza.Utilizzo di modelli Visitor e Composito per creare un flusso filtrato
interface Command {
public int getCost();
}
class SimpleCommand implements Command {
private int cost;
public int getCost() {
return cost;
}
}
class MultiCommand implements Command {
private Command subcommand;
private int repeated;
public int getCost() {
return repeated * subcommand.getCost();
}
public void decrement() {
if (repeated > 0)
repeated--;
}
}
class CommandList implements Command {
private List<Command> commands;
public int getCost() {
return commands.stream().mapToInt(Command::getCost).sum();
}
public void add(Command command) {
commands.add(command);
}
}
interface CommandVisitor {
default void visitSimpleCommand(SimpleCommandCommand command) { }
default void visitMultiCommand(MultiCommand multiCommand) { }
default void visitCommandList(CommandList commandList) { }
}
E 'ora possibile costruire i visitatori per eseguire operazioni quali decrement
. Tuttavia trovo più facile per creare un visitatore di uso generale che i flussi di oggetti di una certa classe in modo che qualsiasi operazione può essere eseguita su di loro:
class MultiCommandCollector implements CommandVisitor {
private final Stream.Builder<MultiCommand> streamBuilder = Stream.builder();
public static Stream<MultiCommand> streamFor(Command command) {
MultiCommandVisitor visitor = new MultiCommandVisitor();
command.accept(visitor);
return visitor.streamBuilder.build();
}
public void visitMultiCommand(MultiCommand multiCommand) {
builder.accept(multiCommand);
}
}
Questo è usato come ci si aspetterebbe. Ad esempio:
MultiCommandCollector.streamFor(command).forEach(MultiCommand::decrement);
Questo ha una significativa limitazione: non può essere utilizzato per modificare la gerarchia come il flusso viene elaborato. Ad esempio, il seguente errore:
CommandListCollector.streamFor(commandList).forEach(cl -> cl.add(command));
Non riesco a pensare a un design elegante alternativo che consentirebbe questo.
La mia domanda è: esiste un'estensione naturale di questo progetto per consentire a un visitatore generico che può anche modificare la gerarchia? In altre parole, c'è un modo in cui il visitatore può visitare un membro, quindi aggiornare la gerarchia prima di visitare il prossimo? È compatibile con l'uso dei flussi?