J'utilise un modèle composite avec plusieurs classes de nœuds feuille qui ont des opérations spécialisées et un modèle de visiteur pour permettre ces opérations. Dans cet exemple, j'ai omis toutes les méthodes évidentes accept
pour plus de clarté.Utilisation de modèles Visiteur et Composite pour créer un flux filtré
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) { }
}
Il est maintenant possible de construire des visiteurs d'effectuer des opérations telles que decrement
. Cependant, je trouve plus facile de créer un visiteur d'usage général qui ruisselle des objets d'une certaine classe de sorte que toute opération peut être effectuée sur eux:
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);
}
}
Il est utilisé comme on peut s'y attendre. Par exemple:
MultiCommandCollector.streamFor(command).forEach(MultiCommand::decrement);
Ceci a une limitation importante: il ne peut pas être utilisé pour modifier la hiérarchie lorsque le flux est traité. Par exemple, l'échec suivant:
CommandListCollector.streamFor(commandList).forEach(cl -> cl.add(command));
Je ne peux pas penser à une conception élégante alternative qui permettrait.
Ma question est la suivante: y a-t-il une extension naturelle à cette conception pour permettre à un visiteur généraliste de modifier la hiérarchie? En d'autres termes, y a-t-il un moyen pour le visiteur de visiter un membre puis de rafraîchir la hiérarchie avant de visiter le suivant? Est-ce compatible avec l'utilisation de flux?