spr*_*ter 5 java design-patterns composite visitor-pattern
我正在使用具有多个叶节点类的复合模式,这些类具有专家操作和访问者模式以允许执行这些操作.在这个例子中,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) { }
}
Run Code Online (Sandbox Code Playgroud)
现在可以建立访问者来执行诸如此类的操作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);
}
}
Run Code Online (Sandbox Code Playgroud)
这可以按照您的预期使用.例如:
MultiCommandCollector.streamFor(command).forEach(MultiCommand::decrement);
Run Code Online (Sandbox Code Playgroud)
这有一个重要的限制:它不能用于在处理流时更改层次结构.例如,以下操作失败:
CommandListCollector.streamFor(commandList).forEach(cl -> cl.add(command));
Run Code Online (Sandbox Code Playgroud)
我想不出一个可以实现这一目标的另类优雅设计.
我的问题是:这个设计有一个自然的扩展,允许一个通用的访问者,也可以改变层次结构?换句话说,有没有办法访问者可以访问一个成员然后刷新层次结构,然后访问下一个?这与流的使用兼容吗?
根据我之前的经验,访问者模式对于查询或重新创建层次结构很有用。查询部分是显而易见的 - 您只需侦听特定类型的子对象,然后构建适合的查询结果。另一个问题,即改变层次结构,则更加困难。
在迭代层次结构时更改层次结构可能真的很困难。因此,我知道两种在实践中效果很好的有用技术。
第一种算法适用于元素可变的情况。第二种算法适用于元素不可变的情况。
希望这可以帮助。