Khi nào nên sử dụng đặc điểm, trái ngược với sự kế thừa và thành phần?


9

Có ba cách phổ biến, AFAIK, để triển khai khả năng sử dụng lại khi nói đến OOP

  1. Kế thừa: thường là đại diện cho một mối quan hệ (một con vịt là một con chim)
  2. Thành phần: thường để thể hiện mối quan hệ có (một chiếc xe có động cơ)
  3. Các đặc điểm (ví dụ: từ khóa đặc điểm trong PHP): ... không thực sự chắc chắn về điều này

Mặc dù đối với tôi, các đặc điểm có thể thực hiện cả hai mối quan hệ đã và đang có, tôi không thực sự chắc chắn rằng nó được dự định để làm mô hình gì. Những loại tình huống được thiết kế cho?


Bạn có thể giải thích thêm một chút về các đặc điểm, nhưng các đặc điểm có thể chỉ là một từ khác cho các tác phẩm?
Trilarion


1
Tôi thực sự muốn biết tại sao là tốt. Không được sử dụng chúng một lần.
Andy

Câu trả lời:


6

Đặc điểm là một cách khác để làm thành phần. Hãy nghĩ về chúng như một cách để tổng hợp tất cả các phần của một lớp trong thời gian biên dịch (hoặc thời gian biên dịch JIT), lắp ráp các triển khai cụ thể của các phần bạn sẽ cần.

Về cơ bản, bạn muốn sử dụng các đặc điểm khi bạn thấy mình tạo các lớp với các kết hợp các tính năng khác nhau. Tình huống này xuất hiện thường xuyên nhất đối với những người viết thư viện linh hoạt cho người khác tiêu thụ. Ví dụ: đây là tuyên bố của một lớp kiểm tra đơn vị tôi đã viết gần đây bằng ScalaTest :

class TestMyClass
  extends WordSpecLike
  with Matchers
  with MyCustomTrait
  with BeforeAndAfterAll
  with BeforeAndAfterEach
  with ScalaFutures

Đơn vị khuôn khổ kiểm tra có một tấn tùy chọn cấu hình khác nhau, và mỗi đội đều có sở thích khác nhau về cách họ muốn làm điều này. Bằng cách đặt các tùy chọn vào các đặc điểm (được trộn lẫn trong sử dụng withtrong Scala), ScalaTest có thể cung cấp tất cả các tùy chọn đó mà không phải tạo tên lớp như WordSpecLikeWithMatchersAndFutures, hoặc một tấn cờ boolean thời gian chạy như thế nào WordSpecLike(enableFutures, enableMatchers, ...). Điều này giúp bạn dễ dàng tuân theo nguyên tắc Mở / Đóng . Bạn có thể thêm các tính năng mới và kết hợp các tính năng mới, chỉ bằng cách thêm một đặc điểm mới. Nó cũng làm cho việc tuân theo Nguyên tắc phân chia giao diện dễ dàng hơn , bởi vì bạn có thể dễ dàng đặt các chức năng không cần thiết vào một đặc điểm chung.

Các đặc điểm cũng là một cách tốt để đặt mã chung vào một số lớp không có ý nghĩa để chia sẻ hệ thống phân cấp thừa kế. Kế thừa là một mối quan hệ gắn bó rất chặt chẽ và bạn không nên trả chi phí đó nếu bạn có thể giúp đỡ. Đặc điểm là một mối quan hệ kết nối lỏng lẻo hơn nhiều. Trong ví dụ của tôi ở trên, tôi đã từng MyCustomTraitdễ dàng chia sẻ việc triển khai cơ sở dữ liệu giả giữa một số lớp kiểm tra không liên quan.

Việc tiêm phụ thuộc đạt được nhiều mục tiêu giống nhau, nhưng trong thời gian chạy dựa trên đầu vào của người dùng thay vì vào thời gian biên dịch dựa trên đầu vào của lập trình viên. Các đặc điểm cũng được dự định nhiều hơn cho các phụ thuộc là một phần về mặt ngữ nghĩa của cùng một lớp. Bạn sắp xếp các phần của một lớp thay vì thực hiện các cuộc gọi đến các lớp khác với các trách nhiệm khác.

Các khung tiêm phụ thuộc đạt được nhiều mục tiêu giống nhau tại thời điểm biên dịch dựa trên đầu vào của lập trình viên, nhưng phần lớn là một cách giải quyết cho các ngôn ngữ lập trình mà không có sự hỗ trợ đặc điểm thích hợp. Các đặc điểm đưa các phụ thuộc này vào vương quốc của trình kiểm tra loại trình biên dịch, với cú pháp rõ ràng hơn, với quy trình xây dựng đơn giản hơn, giúp phân biệt rõ ràng hơn giữa các phụ thuộc thời gian biên dịch và thời gian chạy.


Xin chào, đây là một câu trả lời tuyệt vời. Tôi có thể hỏi làm thế nào để quyết định khi nào nên sử dụng đặc điểm và khi nào sử dụng tiêm phụ thuộc. mà dường như đạt được như nhau.
Extrakun

Quan sát sắc sảo. Xem chỉnh sửa của tôi.
Karl Bielefeldt

Cảm ơn vì đã viết cái này lên. Tôi tò mò về câu trả lời của bạn về những đặc điểm giống như sáng tác @KarlBielefeldt. Lớp của bạn có thể được sử dụng bất cứ nơi nào cần đặc điểm đó, và bạn vẫn sẽ phải chịu sự mong manh giống như với một giao diện thông thường. Vì vậy, nó có vẻ gần hơn với phân nhóm và thừa kế, không? Tôi cũng không chắc nó giống với DI như thế nào ... nếu bạn có các lớp khác nhau được xác định mở rộng các đặc điểm, thì đó không phải là các phụ thuộc cụ thể được xác định ở bất kỳ đâu trong hệ thống phân cấp mà lớp được xác định, thay vì tại điểm đầu / đầu vào của mã? Cảm ơn!
allstar

Các đặc điểm có thể được sử dụng giống như các giao diện, cho các thuộc tính kế thừa của chúng, nhưng đó không phải là những gì làm cho chúng trở nên độc đáo. Các withnhà điều hành là gì phân biệt chúng, và withlà một hoạt động sáng tác. Và có, các đặc điểm thay thế DI mà không cần phải được xác định tại điểm vào của mã. Đó là một trong những điều khiến chúng thích hơn theo ý kiến ​​của tôi.
Karl Bielefeldt
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.