Khi nào cần chuyển một trường chung vào một lớp cơ sở?


16

Tôi hiện có hai lớp dẫn xuất, ABcả hai đều có một trường chung và tôi đang cố xác định xem nó có nên đi vào lớp cơ sở không.

Nó không bao giờ được tham chiếu từ lớp cơ sở và nói rằng nếu tại một thời điểm nào đó, một lớp khác có nguồn gốc, Cthì không có _field1, thì hiệu trưởng của "đặc quyền tối thiểu" (hoặc một cái gì đó) sẽ bị vi phạm nếu nó được không

public abstract class Base
{
    // Should _field1 be brought up to Base?
    //protected int Field1 { get; set; }
}

public class A : Base
{
    private int _field1;
}

public class B : Base
{
    private int _field1;
}

public class C : Base
{
    // Doesn't have/reference _field1
}

18
Tôi nghĩ rằng câu hỏi này là không rõ ràng bởi vì bạn đã không cho chúng tôi bất kỳ ý tưởng về những gì Base, A, B, C, và _field1đang có. Đó là những chi tiết quan trọng không nên bỏ qua; Tôi nghĩ bạn nên chỉnh sửa câu hỏi để nói về những thứ đó.
Tanner Swett

Dựa trên các câu trả lời tôi sẽ: xây dựng lại Xe để có Hệ thống treo ảo, sau đó Xe và Xe đạp có thể có Bánh xe và Thuyền có thể có Phao, sẽ di chuyển trừu tượng lên trên. Tôi thấy rằng nếu sự trừu tượng của tôi dẫn trực tiếp đến các cài đặt cụ thể thì tôi đã không chuyển khái niệm đủ xa lên chuỗi.
Patrick Hughes

6
Đừng sử dụng kế thừa lớp để tránh trùng lặp mã. Sử dụng nó để kế thừa và mở rộng hành vi , tức là đa hình. Di chuyển một trường chung sang một lớp cơ sở nếu và chỉ khi nó là cùng một trường, không phải là hai thông tin không liên quan đến nhau để chia sẻ cùng tên trong bối cảnh tương ứng của chúng.
Brandon

Tại sao bạn có một lớp cơ sở để bắt đầu?
jpmc26

Câu trả lời:


34

Tất cả phụ thuộc vào vấn đề chính xác mà bạn đang cố gắng giải quyết.

Hãy xem xét một ví dụ cụ thể: lớp cơ sở trừu tượng của bạn là Vehiclevà bạn hiện đang có các triển khai cụ thể BicycleCar. Bạn đang xem xét chuyển numberOfWheelstừ BicycleCarsang xe. Bạn có nên làm điều này? Không! Bởi vì không phải xe nào cũng có bánh xe. Bạn đã có thể nói rằng nếu bạn cố gắng thêm một Boatlớp thì nó sẽ bị hỏng.

Bây giờ, nếu lớp cơ sở trừu tượng của bạn WheeledVehiclethì thật hợp lý khi có numberOfWheelsbiến thành viên trong đó.

Bạn cần áp dụng logic tương tự cho vấn đề của mình, vì như bạn có thể thấy, đó không phải là câu trả lời đơn giản hay không.


3
Người ta có thể tạm thời chấp nhận rằng 0 là một số hợp lệOfWheels. Tuy nhiên, cuối cùng bạn có thể thêm một roll()phương thức, tại thời điểm đó, ý tưởng của lớp con đang tìm kiếm trước.
dùng949300

11
Một chiếc thuyền có 0 bánh. Điều đó phá vỡ điều gì?
D Drmmr

14
@DDrmmr Không phải là Thuyền có 0 bánh, mà Bánh xe thậm chí không tồn tại như một khái niệm cho Thuyền - do đó các mô hình của bạn không nên cho phép.
Peter M

10
Quan điểm của tôi là ví dụ này là xấu. Không có gì sai về mặt khái niệm với một chiếc xe (đó là một chiếc thuyền) nói rằng nó có 0 bánh.
D Drmmr

10
Sau đó tất cả sẽ rơi vào địa ngục khi bạn cần lưu trữ một chiếc thuyền chèo.
IllusiveBrian

13

Nói một cách logic, ngoài việc đặt trường được sao chép trong các lớp con so với chung trong lớp cơ sở, có một tùy chọn thứ ba: đó là đưa một lớp con mới vào hệ thống phân cấp có các thuộc tính chung giữa hai lớp. @Pete gợi ý về điều này mà không hoàn toàn đi đến đó.

Sử dụng ví dụ của @ Pete, chúng tôi sẽ giới thiệu một lớp con (có thể trừu tượng) cho Xe có bánh xe đi xuống từ lớp cơ sở ban đầu - trong khi hai lớp con đi xuống từ nó. Do đó, lớp cơ sở ban đầu không bị ô nhiễm với bánh xe, tuy nhiên điểm chung của các bánh xe là DRY (không lặp lại giữa các lớp con có bánh xe).

Tất nhiên, điều này có thể là quá mức cần thiết cho mục đích của bạn, nhưng điều đó được hỗ trợ bởi cơ chế phân cấp lớp.


Đây thực sự là những gì tôi đã quyết định làm (chủ yếu là A và B trùng nhau, vì vậy B sẽ xuất phát từ A).
samis

9

Tôi sẽ chơi người ủng hộ của quỷ ở đây.

Ngay bây giờ bạn không nên làm .

Có phải là KHÔ? Không. Nhưng tốt hơn là có một chút trùng lặp hơn là một sự trừu tượng sớm mà bạn không thể dễ dàng rút lui sau này. Bộ tái cấu trúc để di chuyển một thuộc tính sang một lớp cơ sở chung là dễ dàng. Đi đường khác thì không. Chờ và xem.

Khi đưa ra quyết định này, tôi có xu hướng sử dụng "quy tắc 3": một khi tôi đã lặp lại điều tương tự ở ba nơi khác nhau, và chỉ sau đó, tôi mới xem xét chuyển nó lên chuỗi. NB bạn chỉ ở mức 2.


2
Một quan sát khôn ngoan, tôi sẽ nói, cần thiết để đưa ra quyết định.
radarbob

1
Tôi hầu như đồng ý, nhưng "Ngay bây giờ" (không có mã bổ sung như chúng ta thấy) việc tái cấu trúc theo cả hai hướng là không đáng kể. Nhưng nếu có thêm mã sử dụng trường, việc tái cấu trúc theo cả hai hướng có thể trở nên khó khăn hơn đáng kể.
Doc Brown

2

Nói chung, tôi sẽ chuyển nó đến lớp cơ sở. Tôi không nghĩ có một mục tiêu có / không, bởi vì có một sự đánh đổi ở đây - mang theo những lĩnh vực không sử dụng so với việc giảm độ phức tạp.

Tôi thường thích các lớp cơ sở 'nặng' có chứa bất cứ thứ gì có thể được chia sẻ. Điều này làm cho việc tuần tự hóa các tệp trở nên đơn giản hơn vì bạn không cần các phương thức tuần tự hóa hậu duệ trong mỗi lớp dẫn xuất. Nhưng nếu bạn không có vấn đề đó hoặc một vấn đề tương tự, hoặc có lẽ bạn cần phải làm mọi thứ có thể để giảm mức sử dụng bộ nhớ, thì chỉ giữ các trường nơi bạn cần chúng sẽ ổn.

Một lớp 'trung gian' giới thiệu các trường chung sẽ ổn nếu bạn có số lượng trường rất hạn chế. Nhưng hãy lưu ý rằng cách tiếp cận có thể làm tăng đáng kể độ phức tạp nếu bạn có hàng tá trường được sử dụng trong các kết hợp khác nhau, dẫn đến nhiều lớp trung gian, mỗi lớp giới thiệu một nhóm trường cụ thể. Điều đó có thể trở thành một vấn đề bảo trì.


Ví dụ của tôi là tầm thường, mặc dù nó vẫn là mã sản xuất. Bạn đưa ra một lập luận tốt cho việc "thỏa hiệp" hệ thống phân cấp với lớp cơ sở "nặng", điều mà tôi cũng sẽ thấy mình nghiêng về phía trong trường hợp như vậy.
samis

1
@samis: bạn sử dụng các lớp có tên "A, B, C" và "Base" chỉ với một trường và không có phương thức nào trong mã sản xuất? Tôi nghi ngờ điều đó.
Doc Brown
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.