Một lớp nên biết về các lớp con của nó?


24

Một lớp nên biết về các lớp con của nó? Một lớp có nên làm một cái gì đó cụ thể cho một lớp con cụ thể không?

Bản năng của tôi nói với tôi rằng đó là một thiết kế tồi, nó có vẻ giống như một kiểu chống mẫu nào đó.


6
Thường thì không, nhưng trong trường hợp đặc biệt thì nó hữu ích.
CodeInChaos

Đó một mô hình chống, một mô hình nổi tiếng được gọi là: "Nguyên tắc thay thế Liskov" hoặc đôi khi chỉ là LSP, đọc về nó tại en.wikipedia.org/wiki/Liskov_substlation_principl
Jimmy Hoffa

5
@JimmyHoffa - "Nguyên tắc thay thế Liskov" không phải là tên của một mô hình chống đối. Một mô hình chống có thể vi phạm LSP, nhưng thậm chí không chắc chắn rằng điều này sẽ đúng ở đây. Có thể là, ngay cả khi một loại biết đó là các kiểu con, thì các kiểu con vẫn có thể được thay thế cho cha mẹ của chúng với mâu thuẫn và hiệp phương sai.
Matthew Flynn

4
@MatthewFlynn Có lẽ tôi đang sử dụng LSP một cách lỏng lẻo nhưng theo định nghĩa của tôi, thực tế là tất cả họ đều không đáp ứng các yêu cầu của nhau mà tuân thủ LSP, đó là một yêu cầu mà họ có một sự tách rời để họ không chỉ đồng ý với nhau mà bạn có thể triển khai một lớp con khác không vi phạm LSP. Nếu hệ thống phân cấp tự nhận thức thì việc triển khai bên ngoài không thể đáp ứng LSP mà không thay đổi lớp cơ sở. Có lẽ đó không hoàn toàn là LSP nhưng nó rất gần. và vâng, tôi nên nói rằng vi phạm LSP là mô hình chống
Jimmy Hoffa

2
Một vài lần tôi đã gặp phải điều này, tôi đã tái cấu trúc kiến ​​thức đó thành một phương thức có thể được ghi đè trong một lớp con (hoặc bị ép buộc bằng cách làm cho nó trừu tượng hoặc thuần ảo, hoặc cung cấp một triển khai mặc định hợp lý có thể bị ghi đè).

Câu trả lời:


32

Câu trả lời ngụ ý của khái niệm các lớp là "không".

Bất kỳ hành động, dữ liệu hoặc quan hệ nào bạn đang xử lý là một phần của tất cả các lớp con - sau đó nó sẽ được xử lý trong lớp cha mà không cần kiểm tra loại thực tế. Hoặc nó chỉ áp dụng cho một số lớp con - sau đó bạn phải thực hiện kiểm tra loại thời gian chạy để thực hiện đúng, siêu lớp sẽ phải được thay đổi bất cứ khi nào người khác thừa hưởng từ nó (hoặc nó có thể âm thầm làm sai), những thay đổi trong các lớp dẫn xuất có thể phá vỡ lớp cha không thay đổi, v.v.

Nói tóm lại, bạn nhận được một số hậu quả xấu thường đủ tệ để loại bỏ các giải pháp đó ra khỏi tầm tay. Nếu một vài trong số các lớp con của bạn làm điều tương tự và bạn muốn tránh sao chép mã (thực tế luôn luôn là một điều tốt), một giải pháp tốt hơn là giới thiệu một lớp trung cấp mà tất cả các lớp con đó có thể kế thừa mã.


4
Một ngoại lệ cho quy tắc này: Tài liệu của lớp nên liệt kê các lớp con cục bộ vào thư viện riêng của nó.
Kieveli

3
@Kieveli ... miễn là tài liệu đó được cập nhật.
mouviciel

14
Bất kỳ công cụ tài liệu có thể sử dụng nào cũng có thể vẽ cây thừa kế ...
johannes

13
Tôi không nghĩ đó là một ngoại lệ. Cả lớp vẫn không biết gì. Các tài liệu biết.
Honza Brabec

4
@Kieveli uhh tôi hoàn toàn không đồng ý.
Jimmy Hoffa

16

Không chỉ không nên biết, nó chỉ đơn giản là không thể ! Thông thường, một lớp học có thể được mở rộng mọi lúc, mọi nơi. Nó có thể được mở rộng bởi các lớp thậm chí không tồn tại khi nó được viết.

Một số ngôn ngữ cho phép mở rộng các lớp được điều khiển bởi siêu lớp. Trong Scala, một lớp có thể được đánh dấu là sealed, điều đó có nghĩa là nó chỉ có thể được mở rộng bởi các lớp khác trong cùng một đơn vị biên dịch (tệp nguồn). Tuy nhiên, trừ khi các lớp con đó cũng sealed hoặc final, các lớp con sau đó có thể được mở rộng thêm bởi các lớp khác.

Trong Scala, điều này được sử dụng để mô hình các kiểu dữ liệu đại số đóng, vì vậy Listkiểu Haskell chính tắc :

data List a = Nil | Cons a (List a)

có thể được mô hình hóa trong Scala như thế này:

sealed trait List[+A]

case object Nil extends List[Nothing]

final case class Cons[+A] extends List[A]

Và bạn có thể đảm bảo rằng chỉ có hai phụ "lớp học" tồn tại vì Listsealedvà do đó không thể được bên ngoài mở rộng của tập tin, Consfinalvà do đó không thể được mở rộng ở tất cả và Nillà một objecttrong đó không thể được mở rộng anyway.

Nhưng đây là trường hợp sử dụng cụ thể (mô hình hóa các kiểu dữ liệu đại số thông qua kế thừa) và ngay cả trong trường hợp này, siêu lớp thực sự không biết về các lớp con của nó. Đó là nhiều hơn một đảm bảo cho người sử dụng của các Listloại rằng nếu anh thực hiện một sự phân biệt trường hợp NilCons, sẽ không có bất kỳ khác thay thế nảy lên sau lưng.


Những gì hoạt động trong nhiều ngôn ngữ là thêm một số hình thức abstract internalthành viên.
CodeInChaos

4

Câu trả lời đơn giản là không có.

Nó làm cho mã dễ vỡ và làm hỏng hai nguyên tắc cơ bản của lập trình hướng đối tượng.

  • Nguyên tắc thay thế Liskov
  • Nguyên tắc đóng

1

Vâng, thỉnh thoảng. Ví dụ, khi có một số lượng các lớp con giới hạn tồn tại. Một mô hình khách truy cập là một minh họa về tính hữu ích của phương pháp này.

Ví dụ: tất cả các nút cây cú pháp trừu tượng (AST) của một số ngữ pháp được xác định rõ đều có thể được kế thừa từ một Nodelớp duy nhất thực hiện một mẫu khách truy cập để xử lý tất cả các loại nút.


9
Không, không và không. Điều này không hữu ích và không bao giờ là một giải pháp tốt.
Sulthan

@Sulthan Tôi đã làm việc với AST bên ngoài lớp học và tôi tin rằng người hát không thực sự hiểu câu hỏi. Khách truy cập không phải là một loại nút trên AST, nó là một đối tượng riêng biệt. Nó có thể và nên biết về các đối tượng ngữ pháp. Nhưng một nút AST cấp cao thì không nên.

1
@JohnGaughan Thuật ngữ "biết" làm tôi bối rối. Tất Nodenhiên, lớp cơ sở không chứa bất kỳ tham chiếu trực tiếp nào đến các lớp con của nó. Nhưng nó chứa một acceptphương thức với một Visitortham số. Và Visitorchứa một visitphương thức cho mỗi lớp con. Vì vậy, mặc dù Nodekhông có tài liệu tham khảo trực tiếp đến các lớp con của nó, nó "biết" về chúng một cách gián tiếp, thông qua Visitorgiao diện. Tất cả họ cùng nhau thông qua nó.
điệp khúc

1
@Sulthan Đừng bao giờ nói không bao giờ. Loại tùy chọn là một ví dụ hợp lệ của trường hợp khi siêu lớp biết về hậu duệ. Nhưng như Jorg nói nó sẽ được đánh dấu là niêm phong.
Pavel Voronin

Sau đó là đồng ý: một khách truy cập cần biết những gì nó đang truy cập.

1

Nếu tôi viết một thành phần cho một công ty và sau đó, sau khi tôi rời đi, ai đó sẽ mở rộng nó cho mục đích riêng của họ, tôi có nên được thông báo về điều đó không?

Không!

Tương tự với các lớp học. Tin vào bản năng của bạn.


An ninh công việc ???
Sixty feetersdude

Bạn cao sáu mươi feet vì vậy tôi sẽ không tranh luận với bạn :-) Tuy nhiên, tôi hy vọng ý nghĩa của tôi là sau khi tôi đi và có một công việc khác.
Daniel Hollinrake
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.