Giả sử bạn có một cây phân tích cú pháp, cây cú pháp trừu tượng và biểu đồ luồng điều khiển, mỗi cây có nguồn gốc logic từ cái trước. Về nguyên tắc, có thể dễ dàng xây dựng từng biểu đồ cho cây phân tích, nhưng làm thế nào chúng ta có thể quản lý sự phức tạp của việc cập nhật biểu đồ khi cây phân tích được sửa đổi? Chúng ta biết chính xác cây đã được sửa đổi như thế nào, nhưng làm thế nào để thay đổi có thể được truyền sang các cây khác theo cách không trở nên khó quản lý?
Đương nhiên, biểu đồ phụ thuộc có thể được cập nhật bằng cách tái cấu trúc lại từ đầu mỗi khi biểu đồ đầu tiên thay đổi, nhưng sau đó sẽ không có cách nào để biết chi tiết về các thay đổi trong biểu đồ phụ thuộc.
Tôi hiện có bốn cách để cố gắng giải quyết vấn đề này, nhưng mỗi cách đều có khó khăn.
- Các nút của cây phụ thuộc mỗi nút quan sát các nút có liên quan của cây gốc, tự cập nhật và người quan sát liệt kê các nút cây ban đầu khi cần thiết. Sự phức tạp về khái niệm của điều này có thể trở nên nan giải.
- Mỗi nút của cây ban đầu có một danh sách các nút cây phụ thuộc phụ thuộc vào nó và khi nút thay đổi, nó đặt cờ trên các nút phụ thuộc để đánh dấu chúng là bẩn, bao gồm cả cha mẹ của các nút phụ thuộc suốt đến tận gốc. Sau mỗi thay đổi, chúng tôi chạy một thuật toán giống như thuật toán xây dựng biểu đồ phụ thuộc từ đầu, nhưng nó bỏ qua bất kỳ nút sạch nào và tái tạo lại mỗi nút bẩn, theo dõi xem nút được xây dựng lại có thực sự khác với nút bẩn hay không. Điều này cũng có thể nhận được khó khăn.
- Chúng ta có thể biểu thị kết nối logic giữa biểu đồ gốc và biểu đồ phụ thuộc dưới dạng cấu trúc dữ liệu, giống như một danh sách các ràng buộc, có lẽ được thiết kế bằng ngôn ngữ khai báo. Khi biểu đồ ban đầu thay đổi, chúng ta chỉ cần quét danh sách để khám phá những ràng buộc nào bị vi phạm và cách cây phụ thuộc cần thay đổi để sửa lỗi vi phạm, tất cả được mã hóa dưới dạng dữ liệu.
- Chúng ta có thể xây dựng lại biểu đồ phụ thuộc từ đầu như thể không có biểu đồ phụ thuộc hiện có, sau đó so sánh biểu đồ hiện có và biểu đồ mới để khám phá xem nó đã thay đổi như thế nào. Tôi chắc chắn đây là cách dễ nhất vì tôi biết có sẵn các thuật toán để phát hiện sự khác biệt, nhưng chúng đều khá tốn kém về mặt tính toán và về nguyên tắc có vẻ không cần thiết nên tôi cố tình tránh tùy chọn này.
Cách đúng đắn để đối phó với các loại vấn đề là gì? Chắc chắn phải có một mẫu thiết kế làm cho toàn bộ điều này gần như dễ dàng. Sẽ thật tốt khi có một giải pháp tốt cho mọi vấn đề của mô tả chung này. Liệu lớp vấn đề này có một tên?
Hãy để tôi giải thích về những rắc rối mà vấn đề này gây ra. Vấn đề này xuất hiện ở nhiều nơi, bất cứ khi nào hai phần của dự án hoạt động trên biểu đồ, với mỗi biểu đồ là một đại diện khác nhau của cùng một thứ thay đổi trong khi phần mềm đang chạy. Nó giống như tạo một bộ chuyển đổi cho một giao diện, nhưng thay vì bọc một đối tượng hoặc một số đối tượng cố định, chúng ta cần bọc toàn bộ biểu đồ có kích thước tùy ý.
Mỗi lần tôi thử điều này, tôi kết thúc với một mớ hỗn độn khó hiểu. Luồng điều khiển của người quan sát có thể khó theo dõi khi nó trở nên phức tạp và thuật toán chuyển đổi một biểu đồ này sang biểu đồ khác thường đủ khó để theo dõi khi nó được trình bày rõ ràng và không trải rộng trên nhiều lớp. Vấn đề là dường như không có cách nào để sử dụng chỉ một thuật toán chuyển đổi biểu đồ đơn giản, đơn giản khi biểu đồ gốc đang thay đổi.
Đương nhiên, chúng ta không thể trực tiếp sử dụng thuật toán chuyển đổi biểu đồ thông thường vì điều đó không thể đáp ứng với các thay đổi theo bất kỳ cách nào ngoài việc bắt đầu từ đầu, vậy các lựa chọn thay thế là gì? Có lẽ thuật toán có thể được viết theo kiểu chuyển tiếp, trong đó mỗi bước của thuật toán được biểu diễn dưới dạng một đối tượng với một phương thức cho từng loại nút trong biểu đồ gốc, giống như một khách truy cập. Sau đó, thuật toán có thể được lắp ráp bằng cách kết hợp nhiều khách truy cập đơn giản khác nhau lại với nhau.
Một ví dụ khác: Giả sử bạn có một GUI được trình bày giống như bạn có thể có trong Java Swing, sử dụng JPanels và trình quản lý bố cục. Bạn có thể đơn giản hóa quy trình đó bằng cách sử dụng JPanels lồng nhau thay cho các trình quản lý bố cục phức tạp, do đó, bạn kết thúc với một cây chứa các thùng chứa khác nhau bao gồm các nút chỉ tồn tại cho mục đích bố trí và nếu không thì vô nghĩa. Bây giờ giả sử rằng cùng một cây được sử dụng để tạo GUI của bạn cũng được sử dụng trong một phần khác của ứng dụng của bạn, nhưng thay vì đặt cây ra đồ họa, nó đang làm việc với một thư viện sẽ tạo ra một cây đại diện trừu tượng như một hệ thống các thư mục. Để sử dụng thư viện này, chúng ta cần có một phiên bản của cây không có các nút bố trí; các nút bố trí cần được làm phẳng thành các nút cha của chúng,
Một cách khác để xem xét nó: Chính khái niệm làm việc với những cây đột biến đã vi phạm Luật Demeter . Sẽ không thực sự vi phạm pháp luật nếu cây là một giá trị như cây phân tích cú pháp và cây cú pháp thông thường, nhưng trong trường hợp đó sẽ không có vấn đề gì vì không cần phải cập nhật. Vì vậy, vấn đề này tồn tại như là kết quả trực tiếp của việc vi phạm Luật Demeter, nhưng làm thế nào để bạn tránh điều đó nói chung khi tên miền của bạn dường như là về thao túng cây hoặc đồ thị?
Mẫu tổng hợp là một công cụ tuyệt vời để biến một biểu đồ thành một đối tượng duy nhất và tuân theo Định luật Demeter. Có thể sử dụng mô hình Hợp nhất để biến một loại cây này thành một loại cây khác một cách hiệu quả không? Bạn có thể tạo một cây phân tích cú pháp hỗn hợp để nó hoạt động như một cây cú pháp trừu tượng và thậm chí là một biểu đồ luồng điều khiển không? Có cách nào để làm điều đó mà không vi phạm nguyên tắc trách nhiệm duy nhất ? Mẫu tổng hợp có xu hướng khiến các lớp tiếp thu mọi trách nhiệm mà chúng chạm vào, nhưng có lẽ nó có thể được kết hợp với mẫu Chiến lược bằng cách nào đó.