Thành phần trên thừa kế nhưng


13

Tôi đang cố gắng tự dạy mình về công nghệ phần mềm và đưa ra một số thông tin mâu thuẫn làm tôi bối rối.

Tôi đã học OOP và các lớp / Giao diện trừu tượng là gì và cách sử dụng chúng, nhưng sau đó tôi đang đọc rằng người ta nên 'ưu tiên sáng tác hơn sự kế thừa'. Tôi hiểu thành phần là khi một lớp sáng tác / tạo một đối tượng của lớp khác để sử dụng / tương tác với chức năng của đối tượng mới đó.

Vì vậy, câu hỏi của tôi là ... Tôi có nên sử dụng các lớp và giao diện trừu tượng không? Để không tạo một lớp trừu tượng và mở rộng / kế thừa chức năng của lớp trừu tượng đó trong các lớp cụ thể, và thay vào đó, chỉ cần soạn các đối tượng mới để sử dụng chức năng của lớp khác?

Hoặc, tôi có nên sử dụng thành phần VÀ kế thừa từ các lớp trừu tượng; sử dụng cả hai kết hợp với nhau? Nếu vậy, bạn có thể cung cấp một số ví dụ về cách nó sẽ hoạt động và lợi ích của nó?

Vì tôi cảm thấy thoải mái nhất với PHP, tôi đang sử dụng nó để cải thiện các kỹ năng OOP / SE của mình trước khi chuyển sang các ngôn ngữ khác và chuyển các kỹ năng SE mới có được của tôi, vì vậy các ví dụ sử dụng PHP sẽ được đánh giá cao nhất.


2
"Thành phần ủng hộ thừa kế" là một ý tưởng ngớ ngẩn có ý nghĩa chính xác như "cưa cưa trên máy khoan". Chúng là hai công cụ khác nhau phù hợp để sử dụng trong hai trường hợp sử dụng khác nhau và thời điểm bạn thực sự có thể sử dụng một trong hai công cụ thay thế cho nhau thực sự rất hiếm.
Mason Wheeler

2
"Ưu tiên X hơn Y" không có nghĩa là không bao giờ sử dụng Y, hãy nghĩ xem liệu X có tốt hơn không
Richard Tingle

2
"Thành phần ưu tiên hơn thừa kế" được thể hiện chính xác hơn là "Không bao giờ, bao giờ, sử dụng kế thừa lớp", với sự làm rõ rằng việc thực hiện giao diện không phải là kế thừa và nếu ngôn ngữ bạn chọn chỉ hỗ trợ các lớp trừu tượng, không phải giao diện, kế thừa từ 100% lớp trừu tượng cũng có thể được xem là "không kế thừa".
David Arno

1
@MasonWheeler, không có trường hợp sử dụng hợp lệ cho thừa kế. Nó ít nhất là "ác" một tính năng như "goto".
David Arno

1
@DavidArno Điều đó thật vô lý. Kế thừa là một trong những tính năng hữu ích, hữu ích nhất từng được phát triển trong toàn bộ lịch sử lập trình. Như với bất cứ điều gì hữu ích, có rất nhiều cách để lạm dụng nó, nhưng được sử dụng đúng cách nó sẽ làm tăng mạnh mẽ năng suất và năng suất làm việc của bạn.
Mason Wheeler

Câu trả lời:


19

Thành phần trên Kế thừa có nghĩa là khi bạn muốn sử dụng lại hoặc mở rộng chức năng của một lớp hiện có, thường thì sẽ phù hợp hơn khi tạo một lớp khác sẽ 'bao bọc' lớp hiện có và sử dụng nội bộ của nó. Mẫu trang trí là một ví dụ về điều này.

Kế thừa không phải là một cách mặc định tốt để xử lý các tình huống sử dụng lại bởi vì bạn thường chỉ muốn sử dụng một phần của chức năng của lớp cơ sở và lớp con không thể hỗ trợ toàn bộ hợp đồng của lớp cơ sở theo cách đáp ứng Liskov nguyên tắc .

Phương pháp mẫu là một ví dụ tốt về trường hợp thừa kế phù hợp.

Xem câu trả lời này để biết hướng dẫn về cách chọn giữa thành phần và kế thừa.


+1 để chỉ ra rằng trong trường hợp tái sử dụng một phần của một lớp, phần không được sử dụng sẽ bị bỏ qua rõ ràng hơn với thành phần so với kế thừa.
Lawrence

4

Tôi không đủ quen thuộc với PHP để cung cấp cho bạn các ví dụ cụ thể bằng ngôn ngữ đó, nhưng đây là một vài hướng dẫn mà tôi thấy hữu ích.

Các giao diện / đặc điểm rất hữu ích để xác định hành vi trên nhiều lớp có thể có rất ít điểm chung khác.

Ví dụ: nếu bạn đang làm việc trên một api JSON, bạn có thể xác định một giao diện chỉ định hai phương thức: Bắt đầu vớiJson và và toStatusCode. Điều này sẽ cho phép bạn viết một trình trợ giúp có thể lấy bất kỳ đối tượng nào thực hiện giao diện này và chuyển đổi nó thành một phản hồi http.

Hầu hết thời gian, điều này được ưu tiên hơn so với thừa kế trực tiếp, bởi vì nó ít có khả năng gặp phải vấn đề của lớp cơ sở mong manh, vì nó có xu hướng đối với hệ thống phân cấp lớp nông.

Kế thừa trực tiếp được coi là tốt nhất như một việc bạn làm khi có những lý do thuyết phục để làm như vậy, hơn là những việc bạn làm trừ khi có những lý do thuyết phục không nên làm.

Trong các ngôn ngữ không hỗ trợ triển khai mặc định trong giao diện, có thể là một cách hợp lý để chia sẻ một bộ chức năng cơ bản, nhưng nó thường hạn chế rất nhiều những gì bạn có thể làm với các lớp con (nhiều kế thừa, khi có sẵn, hiếm khi gây đau khổ) . Thông thường, tôi thấy thật đáng để viết các phương pháp chuyển hướng nồi hơi để sử dụng bố cục thay thế.

Thành phần nên là chiến lược mặc định của bạn. Càng nhiều càng tốt, soạn thảo với các giao diện và chuyển chúng thành các đối số của hàm tạo. Điều này sẽ làm cho cuộc sống của bạn dễ dàng hơn nhiều khi viết bài kiểm tra.

Tránh làm việc với các singletons toàn cầu càng nhiều càng tốt, vì so sánh sản lượng dự kiến ​​và thực tế là một nỗi đau đúng nếu một phần của đầu ra phụ thuộc vào trạng thái của đồng hồ hệ thống.

Điều này, tất nhiên, không phải lúc nào cũng có thể. Ví dụ: khung web Play cung cấp thư viện JSON về cơ bản là ngôn ngữ cụ thể của miền. Thay đổi điều này sẽ là một công việc chính, trong đó, thay thế các cuộc gọi đến 'Json.prettyPrint' sẽ chỉ là một phần rất nhỏ.


1

Thành phần là khi một lớp cung cấp một số chức năng bằng cách khởi tạo một lớp (có thể là nội bộ) đã thực hiện chức năng này, thay vì kế thừa từ lớp đó.

Vì vậy, ví dụ, nếu bạn có một lớp mô hình một con tàu, và bây giờ bạn được thông báo rằng con tàu của bạn nên cung cấp một sân bay trực thăng, không phải tự nhiên mà lấy được con tàu của bạn từ một sân bay trực thăng, thay vào đó, bạn nên có tàu của bạn chứa một lớp sân bay trực thăng và phơi bày nó thông qua một số Ship.getHelipad()phương pháp.

Trong những năm cũ (một thập kỷ trước đây), người ta thường xem thừa kế là một cách nhanh chóng và dễ dàng để tổng hợp chức năng, do đó, có rất nhiều ví dụ về loại "tàu được thừa hưởng từ sân bay trực thăng", tất nhiên, rất khập khiễng.

Nhưng dictum "Thành phần ủng hộ thừa kế" đã được diễn đạt cẩn thận để làm rõ rằng đây chỉ là một gợi ý, không phải là một quy tắc. Tác giả của cuốn sách đã đủ cẩn thận để không nói điều gì đó như "ngươi sẽ không bao giờ sử dụng sự kế thừa, chỉ thành phần". Điều này về cơ bản mang đến sự chú ý của cộng đồng công nghệ phần mềm, thực tế là tính kế thừa đã bị lạm dụng quá mức, trong khi trong nhiều trường hợp, thành phần tạo ra các thiết kế rõ ràng, thanh lịch và có thể bảo trì hơn là kế thừa.

Vì vậy, về cơ bản, bản tóm tắt "Thành phần ủng hộ thừa kế" đang gợi ý rằng bất cứ khi nào bạn phải đối mặt với "kế thừa hoặc sáng tác?" Câu hỏi, bạn nên suy nghĩ kỹ chiến lược phù hợp nhất là gì, và hầu hết các cơ hội là chiến lược phù hợp nhất sẽ trở thành thành phần chứ không phải kế thừa.

Nhưng vì đây không phải là một quy tắc, bạn cũng nên nhớ rằng có nhiều trường hợp thừa kế là tự nhiên hơn. Nếu bạn sử dụng thành phần ở đó nơi bạn nên sử dụng tính kế thừa, nhiều tệ nạn sẽ xảy ra với mã của bạn.

Để quay trở lại ví dụ về tàu, nếu tàu của bạn cần cung cấp giao diện để tương tác với a FloatingMachine, thì việc lấy nó từ một FloatingMachinelớp trừu tượng , điều rất có thể đến từ Machinelớp trừu tượng khác .

Dưới đây là quy tắc ngón tay cái cho câu trả lời cho thành phần so với câu hỏi thừa kế:

Lớp của tôi có mối quan hệ "là" với giao diện mà nó cần phơi bày không? Nếu có, sử dụng thừa kế. Nếu không, sử dụng thành phần.

Một con tàu "là một" máy nổi và một máy nổi "là một" máy. Vì vậy, thừa kế là hoàn toàn tốt cho những người. Nhưng một con tàu dĩ nhiên không phải là sân bay trực thăng. Vì vậy, nó tốt hơn soạn các chức năng của sân bay trực thăng.

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.