2016-04-06 13 views
5

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?

Trả lời

0

Trong kinh nghiệm trước đây của tôi, Mô hình khách truy cập hữu ích để truy vấn hoặc tạo lại cấu trúc phân cấp. Phần truy vấn là hiển nhiên - bạn chỉ cần lắng nghe các loại đối tượng con cụ thể và sau đó xây dựng kết quả truy vấn vì nó phù hợp. Câu hỏi khác, thay đổi hệ thống phân cấp, khó khăn hơn.

Có thể thực sự khó thay đổi cấu trúc phân cấp trong khi lặp qua cấu trúc phân cấp. Vì vậy, tôi biết về hai kỹ thuật hữu ích hoạt động tốt trong thực tế.

  1. Khi truy cập hệ thống phân cấp, hãy tạo danh sách các đối tượng cần thay đổi. Không thay đổi chúng cho đến khi hoàn thành việc truy cập. Khách truy cập cụ thể có thể tạo danh sách các đối tượng quan tâm làm thành viên riêng tư của mình. Khi nó hoàn thành lượt truy cập, nó sẽ hiển thị danh sách các đối tượng dưới dạng kết quả của nó. Chỉ sau đó bắt đầu lặp qua danh sách kết quả và thực hiện thay đổi đối với các đối tượng .
  2. Khi truy cập hệ thống phân cấp, khi bạn truy cập phần tử, hãy tạo bản sao của phần tử. Nếu phần tử cần được thay đổi, hãy tạo phiên bản đã thay đổi. Nếu không, nếu các phần tử không cần thay đổi, chỉ cần trả lại thành phần tử mới . Sau khi toàn bộ lượt truy cập được thực hiện, bạn sẽ có hệ thống phân cấp mới với tất cả các sửa đổi được thực hiện như dự định. Hệ thống phân cấp cũ có thể là bị hủy đăng ký sau đó, và người thu gom rác sẽ thu thập các yếu tố đó đã được thay thế bằng các yếu tố mới.

Thuật toán đầu tiên được áp dụng khi các yếu tố có thể thay đổi. Thuật toán thứ hai được áp dụng khi các phần tử không thay đổi.

Hy vọng điều này sẽ hữu ích.

Các vấn đề liên quan