我正在使用复合模式,其中包含多个叶节点类,这些类具有专业操作和访问者模式,以允许执行这些操作。在此示例中,为了清晰起见,我省略了所有明显的accept
方法。
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) { }
}
现在可以构建访问者来执行像 decrement
这样的操作。然而,我发现更容易创建一个通用的访问者,它可以对某个类的对象进行流处理,这样就可以对它们执行任何操作:
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);
}
}
这是按照您预期使用的。例如:
MultiCommandCollector.streamFor(command).forEach(MultiCommand::decrement);
这有一个显著的限制:在处理流时,它无法用于改变层次结构。例如,以下操作将失败:
CommandListCollector.streamFor(commandList).forEach(cl -> cl.add(command));
我想不出另一个优雅的设计方案来实现这个功能。
我的问题是:是否有自然的扩展方式可以允许一个通用的访问者同时改变层次结构?换句话说,访问者可以在访问一个成员后刷新层次结构再访问下一个吗?这是否与使用流兼容?