Tôi đang sử dụng mẫu tổng hợp với nhiều lớp nút lá có hoạt động chuyên gia và mẫu khách truy cập để cho phép các hoạt động đó được thực hiện. Trong ví dụ này, tôi đã loại bỏ tất cả các phương thức rõ ràng accept
để làm rõ.Sử dụng mẫu Khách truy cập và Tổng hợp để tạo luồng đã lọc
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) { }
}
Giờ đây, bạn có thể tạo khách truy cập để thực hiện các hoạt động như decrement
. Tuy nhiên tôi thấy nó dễ dàng hơn để tạo ra một người truy cập mục đích chung mà dòng đối tượng của một lớp nào đó để cho bất kỳ hoạt động có thể được thực hiện trên chúng:
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);
}
}
này được sử dụng như bạn mong đợi. Ví dụ:
MultiCommandCollector.streamFor(command).forEach(MultiCommand::decrement);
Điều này có một giới hạn đáng kể: không thể sử dụng để thay đổi thứ bậc khi luồng được xử lý. Ví dụ: các lỗi sau không thành công:
CommandListCollector.streamFor(commandList).forEach(cl -> cl.add(command));
Tôi không thể nghĩ ra một thiết kế thanh lịch thay thế cho phép điều này.
Câu hỏi của tôi là: có phần mở rộng tự nhiên cho thiết kế này để cho phép khách truy cập có mục đích chung cũng có thể thay đổi cấu trúc phân cấp không? Nói cách khác, có cách nào để khách truy cập có thể truy cập vào một thành viên sau đó làm mới phân cấp trước khi truy cập vào thứ bậc tiếp theo không? Điều này có tương thích với việc sử dụng luồng không?