Không phải là hệ thống phân cấp thành phần sâu sắc của Bad.


19

Xin lỗi nếu "Cấu trúc phân cấp" không phải là một điều, nhưng tôi sẽ giải thích ý của tôi trong câu hỏi.

Không có bất kỳ lập trình viên OO nào không bắt gặp một biến thể "Giữ phân cấp thừa kế phẳng" hoặc "Thích thành phần hơn thừa kế", v.v. Tuy nhiên, hệ thống phân cấp thành phần sâu dường như cũng có vấn đề.

Giả sử chúng ta cần một tập hợp các báo cáo chi tiết về kết quả của một thử nghiệm:

class Model {
    // ... interface

    Array<Result> m_results;
}

Mỗi kết quả có tính chất nhất định. Chúng bao gồm thời gian thử nghiệm, cũng như một số dữ liệu meta từ mỗi giai đoạn thử nghiệm:

enum Stage {
    Pre = 1,
    Post
};

class Result {
    // ... interface

    Epoch m_epoch;
    Map<Stage, ExperimentModules> m_modules; 
}

Tuyệt. Bây giờ, mỗi mô-đun thử nghiệm có một chuỗi mô tả kết quả của thử nghiệm, cũng như một tập hợp các tham chiếu đến các bộ mẫu thử nghiệm:

class ExperimentalModules {
    // ... interface

    String m_reportText;
    Array<Sample> m_entities;
}

Và sau đó mỗi mẫu có ... tốt, bạn sẽ có được hình ảnh.

Vấn đề là nếu tôi đang mô hình hóa các đối tượng từ miền ứng dụng của mình, điều này có vẻ như rất phù hợp tự nhiên, nhưng vào cuối ngày, a Resultchỉ là một thùng chứa dữ liệu câm! Có vẻ không đáng để tạo ra một nhóm lớn các lớp cho nó.

Giả sử rằng các cấu trúc dữ liệu và các lớp được hiển thị ở trên mô hình chính xác các mối quan hệ trong miền ứng dụng, có cách nào tốt hơn để mô hình hóa một "kết quả" như vậy, mà không cần dùng đến một hệ thống phân cấp thành phần sâu? Có bất kỳ bối cảnh bên ngoài nào sẽ giúp bạn xác định xem một thiết kế như vậy có phải là một thiết kế tốt hay không?


Không hiểu phần bối cảnh bên ngoài.
Tulains Córdova 4/11/2016

@ TulainsCórdova điều tôi đang cố gắng hỏi ở đây là "có những tình huống mà bố cục sâu là một giải pháp tốt" không?
AwesomeSauce 4/11/2016

Tôi đã thêm một câu trả lời.
Tulains Córdova 4/11/2016

5
Đúng chính xác. Các vấn đề mọi người cố gắng khắc phục bằng cách thay thế tính kế thừa bằng thành phần không biến mất một cách kỳ diệu chỉ vì bạn đã thay đổi một chiến lược tổng hợp tính năng cho một chiến lược khác. Cả hai đều là giải pháp để quản lý sự phức tạp và sự phức tạp đó vẫn còn đó và phải được xử lý theo một cách nào đó.
Mason Wheeler

3
Tôi không thấy bất cứ điều gì sai với các mô hình dữ liệu sâu. Nhưng tôi cũng không thấy làm thế nào bạn có thể mô hình hóa điều này bằng sự kế thừa vì đó là mối quan hệ 1: N ở mỗi lớp.
usr

Câu trả lời:


17

Đây là những gì mà Luật Demeter / nguyên tắc ít kiến ​​thức hướng tới. Người dùng Modelkhông nhất thiết phải biết về ExperimentalModules'giao diện để thực hiện công việc của họ.

Vấn đề chung là khi một lớp kế thừa từ một loại khác hoặc có một trường công khai với một loại nào đó hoặc khi một phương thức lấy một kiểu làm tham số hoặc trả về một kiểu, các giao diện của tất cả các loại đó trở thành một phần của giao diện hiệu quả của lớp tôi. Câu hỏi trở thành: những loại mà tôi phụ thuộc vào: đang sử dụng những điểm đó của toàn bộ lớp học của tôi? Hay họ chỉ là chi tiết thực hiện mà tôi đã vô tình tiếp xúc? Bởi vì nếu chúng là chi tiết triển khai, tôi chỉ tiếp xúc với chúng và cho phép người dùng của lớp tôi phụ thuộc vào họ - khách hàng của tôi giờ đây được liên kết chặt chẽ với các chi tiết triển khai của tôi.

Vì vậy, nếu tôi muốn cải thiện sự gắn kết, tôi có thể hạn chế sự ghép nối này bằng cách viết thêm các phương thức làm công cụ hữu ích, thay vì yêu cầu người dùng tiếp cận với các cấu trúc riêng tư của tôi. Ở đây, chúng tôi có thể cung cấp các phương pháp để tìm kiếm hoặc lọc kết quả. Điều đó làm cho lớp của tôi dễ dàng hơn để cấu trúc lại, vì bây giờ tôi có thể thay đổi biểu diễn bên trong mà không cần thay đổi giao diện.

Nhưng điều này không phải là không có chi phí - giao diện của lớp tiếp xúc của tôi giờ trở nên cồng kềnh với các hoạt động không phải lúc nào cũng cần thiết. Điều này vi phạm Nguyên tắc phân chia giao diện: Tôi không nên ép buộc người dùng phụ thuộc vào nhiều hoạt động hơn thực tế họ sử dụng. Và đó là nơi thiết kế quan trọng: Thiết kế là quyết định nguyên tắc nào quan trọng hơn trong bối cảnh của bạn và tìm kiếm một sự thỏa hiệp phù hợp.

Khi thiết kế một thư viện phải duy trì khả năng tương thích nguồn trên nhiều phiên bản, tôi sẽ có xu hướng tuân theo nguyên tắc ít kiến ​​thức nhất một cách cẩn thận hơn. Nếu thư viện của tôi sử dụng một thư viện khác trong nội bộ, tôi sẽ không bao giờ tiết lộ bất cứ điều gì được xác định bởi thư viện đó cho người dùng của mình. Nếu tôi cần để lộ một giao diện từ thư viện nội bộ, tôi sẽ tạo một đối tượng trình bao bọc đơn giản. Các mẫu thiết kế như Mẫu cầu hoặc Mẫu mặt tiền có thể giúp ở đây.

Nhưng nếu các giao diện của tôi chỉ được sử dụng nội bộ hoặc nếu các giao diện tôi sẽ hiển thị là rất cơ bản (một phần của thư viện tiêu chuẩn hoặc thư viện cơ bản đến mức không bao giờ có ý nghĩa để thay đổi nó), thì có thể vô ích để che giấu những giao diện này. Như thường lệ, không có câu trả lời nào phù hợp cho tất cả mọi người.


Bạn đã đề cập đến một mối quan tâm lớn mà tôi đang có; ý tưởng mà tôi phải tiếp cận sâu rộng để thực hiện để làm một cái gì đó hữu ích ở mức độ trừu tượng cao hơn. Một cuộc thảo luận rất hữu ích, cảm ơn.
AwesomeSauce 4/11/2016

7

Không phải là hệ thống phân cấp thành phần sâu sắc của Bad.

Tất nhiên. Quy tắc thực sự nên nói "giữ tất cả các thứ bậc càng phẳng càng tốt."

Nhưng hệ thống phân cấp thành phần sâu ít giòn hơn hệ thống phân cấp thừa kế sâu và linh hoạt hơn để thay đổi. Theo trực giác, điều này sẽ không gây ngạc nhiên; thứ bậc gia đình là cùng một cách. Mối quan hệ của bạn với người thân máu của bạn được cố định trong di truyền; mối quan hệ của bạn với bạn bè và vợ / chồng của bạn thì không.

Ví dụ của bạn không tấn công tôi như là một "thứ bậc sâu sắc." Một hình thức kế thừa từ một hình chữ nhật kế thừa từ một tập hợp các điểm kế thừa từ tọa độ x và y, và tôi thậm chí còn chưa nhận được một đầu hơi đầy đủ.


4

Diễn giải Einstein:

giữ tất cả các thứ bậc càng phẳng càng tốt, nhưng không tâng bốc

Có nghĩa là nếu vấn đề bạn đang lập mô hình là như vậy, bạn không nên hiểu về mô hình hóa như vậy.

Ứng dụng này chỉ là một bảng tính khổng lồ, sau đó bạn không phải lập mô hình phân cấp thành phần như hiện tại. Nếu không thì làm đi. Tôi không nghĩ rằng điều này là vô cùng sâu sắc. Chỉ cần giữ các getters trả lại các bộ sưu tập lười biếng nếu việc điền vào các bộ sưu tập đó là tốn kém, như yêu cầu chúng vào một kho lưu trữ kéo chúng tạo thành một cơ sở dữ liệu. Ý tôi là lười biếng, đừng tập trung chúng cho đến khi chúng cần thiết.


1

Có, bạn có thể mô hình hóa nó như các bảng quan hệ

Result {
    Id
    ModelId
    Epoch
}

vv thường có thể dẫn đến lập trình dễ dàng hơn và ánh xạ đơn giản vào cơ sở dữ liệu. nhưng với cái giá là mất đi sự mã hóa cứng của các mối quan hệ của bạn


0

Tôi thực sự không biết làm thế nào để giải quyết vấn đề này trong Java, bởi vì Java được xây dựng xung quanh ý tưởng rằng mọi thứ đều là một đối tượng. Bạn không thể loại bỏ các lớp trung gian bằng cách thay thế chúng bằng một từ điển vì các loại trong các đốm dữ liệu của bạn không đồng nhất (chẳng hạn như dấu thời gian + danh sách hoặc chuỗi + danh sách ...). Việc thay thế một lớp container bằng trường của nó (ví dụ: chuyển dọc theo biến "m_epoch" bằng "m_modules") đơn giản là xấu, bởi vì nó đang tạo ra một đối tượng ẩn (bạn không thể có một đối tượng mà không có đối tượng khác) lợi ích.

Trong ngôn ngữ định kiến ​​của tôi (Python), quy tắc ngón tay cái của tôi sẽ không tạo ra một đối tượng nếu không có logic cụ thể (ngoại trừ nhận và cài đặt cơ bản) thuộc về nó. Nhưng với những hạn chế của bạn, tôi nghĩ hệ thống phân cấp thành phần bạn có là thiết kế tốt nhất có thể.

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.