2016-02-07 16 views
33

Tôi đã đọc điều đó với Scala, thường được khuyên nên sử dụng Traits thay vì Abstract classes để mở rộng một lớp cơ sở.Thành phần khách hàng Scala với Traits vs triển khai lớp trừu tượng

Mẫu thiết kế và bố cục tốt sau đây có phù hợp không? Đây có phải là cách các Đặc điểm được dự định thay thế Tóm tắt không?

  • lớp khách hàng (với def Function1)
  • trait1 lớp (ghi đè Function1)
  • trait2 lớp (ghi đè Function1)
  • specificClient1 mở rộng khách hàng với trait1
  • specificClient2 mở rộng khách hàng với trait2

Trả lời

66

Tôi không biết nguồn của bạn là gì cho tuyên bố rằng bạn nên thích những đặc điểm trên các lớp trừu tượng trong Scala, nhưng lại là một vài lý do không phải tới:

  1. Đặc điểm phức tạp Java tương thích. Nếu bạn có một đặc điểm với một đối tượng đồng hành, các phương thức gọi trên đối tượng đồng hành từ Java yêu cầu cú pháp MyType$.MODULE$.myMethod kỳ quái. Đây không phải là trường hợp cho các lớp trừu tượng với các đối tượng đồng hành, được thực hiện trên JVM như một lớp đơn với các phương thức tĩnh và ví dụ. Việc thực hiện một đặc điểm Scala với các phương thức cụ thể trong Java thậm chí còn khó chịu hơn.
  2. Thêm phương pháp có triển khai vào một đặc điểm breaks binary compatibility theo cách thêm các phương thức cụ thể vào lớp học.
  3. Các đặc điểm dẫn đến nhiều mã byte hơn và một số chi phí bổ sung liên quan đến việc sử dụng các phương thức giao nhận.
  4. Đặc điểm mạnh mẽ hơn, điều này rất tệ - nói chung bạn muốn sử dụng tính trừu tượng mạnh mẽ nhất để hoàn thành công việc. Nếu bạn không cần loại thừa kế mà họ hỗ trợ (và rất thường xuyên bạn không), tốt hơn là không có quyền truy cập vào nó.

Lý do cuối cùng là quan trọng nhất trong quan điểm của tôi. Ít nhất một vài vấn đề khác là might get fixed trong các phiên bản tương lai của Scala, nhưng nó sẽ vẫn là trường hợp mặc định cho các lớp sẽ hạn chế các chương trình của bạn theo cách (ít nhất là cho là) ​​phù hợp với thiết kế tốt. Nếu bạn quyết định bạn thực sự thực sự muốn sức mạnh được cung cấp bởi các đặc điểm, họ vẫn sẽ ở đó, nhưng đó sẽ là một quyết định mà bạn đưa ra, chứ không phải thứ bạn vừa mới bỏ qua.

Vì vậy không, trong trường hợp không có thông tin khác, tôi khuyên bạn nên sử dụng một lớp trừu tượng (lý tưởng là một lớp niêm phong) và hai lớp cụ thể cung cấp triển khai.

+2

Là chú thích, cách tiếp cận của Scala để tuyến tính hóa _is_ một giải pháp thông minh cho "vấn đề" của đa thừa kế, và khi bạn cần nó hoạt động khá tốt (ngoại trừ một vài thứ như trường). Nhưng bạn không bao giờ nên sử dụng một cái gì đó chỉ vì nó thông minh. –

+1

Cảm ơn, câu trả lời cho câu hỏi của tôi. Nguồn của tôi là https://www.safaribooksonline.com/library/view/scala-cookbook/9781449340292/ch04s13.html. Câu trả lời của bạn có ý nghĩa hơn mặc dù – kliew

+1

Với Scala [2.12] (http://www.scala-lang.org/news/2.12.0) làm # 1-3 vẫn áp dụng vis-a-vis '" Một đặc điểm biên dịch trực tiếp một giao diện với các phương thức mặc định. Điều này cải thiện khả năng tương thích nhị phân và khả năng tương tác Java. "'? Tất nhiên # 4 là lý do đủ để chọn một 'lớp trừu tượng' trên một đặc điểm', tôi tin. @TravisBrown –

2

OTOH, các đặc điểm cho phép bạn xây dựng và kiểm tra chức năng của các đối tượng phức tạp theo kiểu chi tiết và sử dụng lại logic lõi để cung cấp các hương vị khác nhau. Ví dụ, một đối tượng miền có thể được triển khai đến một máy chủ dữ liệu, nó vẫn tồn tại trong cơ sở dữ liệu, trong khi máy chủ web có thể sử dụng các phiên bản chỉ đọc của cùng một đối tượng được cập nhật từ máy chủ dữ liệu.

Không có gì phù hợp cho mọi trường hợp. Sử dụng đúng cấu trúc cho nhiệm vụ trong tầm tay. Đôi khi thực tế của một triển khai mang đến các vấn đề ánh sáng cho các trường hợp sử dụng cụ thể mà không biết tại thời điểm thiết kế. Tái triển khai bằng cách sử dụng các giả định và cấu trúc khác nhau có thể mang lại kết quả đáng ngạc nhiên.

Các vấn đề liên quan