Làm cách nào để lưu trữ nhiều chế độ xem dữ liệu trong bộ nhớ?


8

Tôi có một loạt các mô-đun. Tôi có thể chia các mô-đun này thành các danh mục khác nhau hoàn chỉnh và không chồng chéo. Ví dụ, có ba loại, với id có thể được diễn tả như Animal, Vegetable, và Mineral. Tôi tiếp tục chia các danh mục này thành các danh mục con, một lần nữa là khác biệt, đầy đủ và không trùng lặp. Ví dụ, id có thể được diễn tả như Mammal, Reptile, Legume, Root, Rock, Gem. Cuối cùng, bên dưới các loại này, có các module mình, ví dụ như Cat, Dog, Iguana, Bean, Quartz, Emerald,, vv

Phân cấp danh mục

Dưới đây là các trường hợp sử dụng phổ biến của tôi:

  1. Tôi cần gọi các phương thức khác nhau trên tất cả các mô-đun.
  2. Tôi cần phải nhận được phẳng snapshot cho trang thái hiện tại của tất cả các dữ liệu trên tất cả các mô-đun.
  3. Tôi cần gọi các phương thức khác nhau trên tất cả các mô-đun trong một danh mục cụ thể (nhưng không phải là danh mục con).
  4. Tôi cần gọi các phương thức khác nhau trên một mô-đun cụ thể dựa trên ID đã biết.
    • Đây có thể là "làm một cái gì đó" hoặc "cho tôi biết một số dữ liệu về bản thân"
  5. Tôi cần lưu trữ dữ liệu tổng hợp về tất cả các mô-đun trong một danh mục cụ thể (nhưng không phải là danh mục con).

Tôi nên lưu trữ dữ liệu này như thế nào?

Một số sự thật có liên quan khác:

  • Các thể loại được thiết lập trong thời gian chạy
    • Như vậy, các mô-đun cấp dưới cùng chia sẻ một giao diện chung.
  • Khi chúng được thiết lập, chúng không thay đổi trong lần chạy cụ thể đó - chúng dựa trên dữ liệu trong các tệp cấu hình.

Đây là những gì tôi hiện đang làm:

  1. Tôi có một lớp có chứa a Map<Category, CategoryDataStructure>. Lớp này cũng duy trì Collection<Module> chế độ xem riêng biệt của dữ liệu để sử dụng với yêu cầu # 2.
  2. CategoryDataStructuređã xâu chuỗi các phương thức ủy nhiệm gửi phương thức gọi xuống chuỗi, thông qua SubCategoryDataStructure.
  3. CategoryDataStructure cũng lưu trữ dữ liệu tổng hợp được sử dụng trong yêu cầu # 5.

Nó hoạt động, nhưng nó thực sự khá khó sử dụng. Toàn bộ điều là trạng thái / đột biến và khó thay đổi. Nếu tôi muốn thêm hành vi mới, tôi phải thêm nó ở nhiều nơi. Hiện tại các cấu trúc dữ liệu cũng có rất nhiều logic kinh doanh; Các phương pháp ủy nhiệm. Ngoài ra, cấu trúc dữ liệu cha mẹ phải thực hiện nhiều logic nghiệp vụ để tạo ra một mô-đun cụ thể và đó là cấu trúc dữ liệu mẹ nếu cần và cấu trúc dữ liệu của cha mẹ đó nếu cần.

Tôi đang tìm cách tách logic logic quản lý dữ liệu ra khỏi cấu trúc dữ liệu, nhưng do việc lồng nhau rất phức tạp. Dưới đây là một số tùy chọn khác mà tôi đã xem xét:

  1. Tạo một đơn giản Map<Category, Map<Subcategory, Module>>và đặt tất cả các mã để giữ trạng thái của nó trong một lớp khác. Mối quan tâm của tôi khi thực hiện điều này là các yêu cầu số 1 và số 2, sẽ rất khó để giữ chế độ xem nhất quán vì bây giờ tôi sẽ có hai cấu trúc dữ liệu khác nhau đại diện cho cùng một dữ liệu.
  2. Thực hiện mọi thứ trong một cấu trúc dữ liệu phẳng và lặp qua toàn bộ cấu trúc khi tôi đang tìm kiếm một danh mục cụ thể hoặc danh mục phụ.

Bạn đã xem xét việc chia nhỏ trách nhiệm "tìm ra đối tượng nào trong hệ thống phân cấp để kiểm tra hoặc sử dụng" bằng cách sử dụng một hoặc nhiều Khách truy cập chưa?

@Snowman Tôi chưa xem xét lựa chọn đó; bạn có đề xuất lưu trữ dữ liệu bằng phẳng không, và sau đó khi tôi cần gọi một phương thức, hãy gửi khách truy cập đến mọi người và kiểm tra xem có điều gì cần phải xảy ra trong handleVisitorlớp không?
durron597

Nó phức tạp hơn một chút, tôi chỉ muốn chắc chắn trước khi tôi gõ một câu trả lời.

Có lẽ bạn có thể lật cấu trúc từ trên xuống và tiến hành từ dưới lên: thing.getType () trả về "Animal" Điều đó khá bằng phẳng.
noumenal

Câu trả lời:


6

Có vẻ như vấn đề cốt lõi ở đây là bạn có các đối tượng được sắp xếp theo thứ bậc dựa trên danh tính của chúng, nhưng đang sử dụng chúng theo cách không phân cấp.

Một sự tương tự sẽ được lưu trữ các tệp trong các thư mục dựa trên loại tệp của chúng, nhưng tìm kiếm qua từng thư mục và chỉ tải một số thư mục nhất định dựa trên một số tiêu chí khác với loại.


Tôi đang tìm cách tách logic logic quản lý dữ liệu ra khỏi cấu trúc dữ liệu, nhưng do việc lồng nhau rất phức tạp. Dưới đây là một số tùy chọn khác mà tôi đã xem xét:

Đây là một mục tiêu tốt và có một cách dễ dàng để bắt đầu phân chia trách nhiệm mà không cần một người tái cấu trúc chính: sử dụng Khách truy cập .

Ý tưởng là nếu bạn cần kiểm tra hoặc chỉ hoạt động trên một số yếu tố nhất định trong hệ thống phân cấp, bạn đặt logic đó vào chính khách truy cập. Sau đó, bạn có thể viết nhiều khách truy cập, mỗi khách truy cập hoạt động trên các yếu tố khác nhau và thực hiện các hành động khác nhau.

Mỗi đơn vị logic hiện được khép kín cho một khách truy cập cụ thể . Điều này giúp tăng cường tính SRP của mã của bạn. Nếu bạn cần thay đổi cách thực hiện một thao tác, bạn chỉ làm như vậy trong khách truy cập thực hiện logic đó. Hệ thống phân cấp đối tượng của bạn nên giữ nguyên, trừ những thay đổi bề ngoài để lộ dữ liệu cần thiết.

Có nhiều cách để triển khai khách truy cập tùy thuộc vào các mục tiêu cụ thể, nhưng ý tưởng chung là mỗi nút trong hệ thống phân cấp chấp nhận một đối tượng khách truy cập. Việc thực hiện của nó trông như thế này và có thể được nhồi vào một số lớp cha trừu tượng:

public class Node {
  public void accept(Visitor v) {
    v.accept(this);
    for (Node child : children) {
      child.accept(v);
    }
  }
}

Điều này đảm bảo rằng cho dù bạn kết nối các nút của mình như thế nào trong thời gian chạy, mọi nút sẽ được xử lý.

Khách truy cập của bạn trông như thế này:

public interface Visitor {
  accept(Node n);
}

accept(Node)Phương pháp của khách truy cập là nơi công việc thực sự được thực hiện. Bạn sẽ cần kiểm tra nút và có điều kiện làm những việc khác nhau (bao gồm bỏ qua nút).


Ví dụ: bạn có thể làm như sau:

Node root = ...;

// Print information on the hierarchy.
root.accept(new DebugVisitor());

// Does stuff with modules, ignores subcategories.
root.accept(new FrobnicateModulesVisitor());

// Eats vegetables, ignores animals and minerals.
root.accept(new EatYourVegetableVisitor());

Mỗi khách truy cập là một lớp khép kín chứa logic cho từng hoạt động mà không cần trộn lẫn mối quan tâm với các khách truy cập khác hoặc các nút.


câu hỏi nhanh liên quan đến lớp Note của bạn: "trẻ em" được định nghĩa ở đâu ... hoặc đây hoàn toàn là một ví dụ minh họa?

@ Không có gì được định nghĩa, đó hoàn toàn là minh họa. Tôi giả sử độc giả sẽ quen thuộc với lý thuyết đồ thị và cây cối.

1

Mức lồng nhau sâu cho thấy rằng bạn nên cấu trúc lại các hành động thành các hàm nhỏ hơn, có thể được xâu chuỗi bằng cách sử dụng các câu lệnh return. Nếu bạn cần áp dụng cùng một phương thức cho nhiều đầu vào, bạn có thể tận dụng lợi thế function.apply()trong Java 8.

Giả sử rằng các mục khác nhau không chia sẻ bất kỳ thuộc tính nào, bạn có thể triển khai một giao diện , yêu cầu một bộ phương thức cụ thể được triển khai. Đối với mỗi cấp I sẽ tạo ra một giao diện, sau đó được mở rộng cho mỗi sub-node, ví dụ: Entity, Phylum, Species. Ngoài ra, bạn cần ba lớp cho mỗi trong ba thực thể.

Dữ liệu có thể được lưu trữ dưới dạng các thuộc tính của các thể hiện đối tượng. Để đạt được một ảnh chụp nhanh, tôi sẽ lặp lại dữ liệu bằng cách sử dụng function.apply().


Chào, cảm ơn cho câu trả lời của bạn. Các yếu tố mức đáy làm chia sẻ một giao diện chung, tôi nghĩ đó sẽ là rõ ràng khi tôi nói tất cả chúng đều được tạo ra trong thời gian chạy, nhưng tôi đã chỉnh sửa để thêm một câu để làm rõ thời điểm đó.
durron597

Dường như với tôi rằng bạn cũng cần một giao diện cho cấp độ tiếp theo, nhưng tôi có thể sai.
năm15
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.