2012-05-18 21 views
15

Tôi biết rằng bạn không được phép kế thừa từ các lớp chữ thường, nhưng bạn sẽ làm gì khi thực sự cần? Chúng ta có hai lớp trong một hệ thống phân cấp, cả hai đều chứa nhiều trường và chúng ta cần có thể tạo ra các cá thể của cả hai trường. Dưới đây là lựa chọn của tôi:Làm thế nào để sử dụng một lớp chữ thường khi cần phân cấp?

  • Nếu tôi muốn làm cho siêu lớp một lớp thông thường thay vì một lớp hợp - Tôi muốn mất tất cả các trường hợp lớp tốt lành như toString, bằng, phương pháp hashCode, vv
  • Nếu Tôi giữ nó như là một trường hợp lớp, tôi muốn phá vỡ các quy tắc của không kế thừa từ các trường hợp lớp học.
  • Nếu tôi sử dụng bố cục trong lớp trẻ em - tôi phải viết nhiều phương pháp và chuyển hướng chúng sang lớp khác - điều đó có nghĩa là rất nhiều công việc và sẽ cảm thấy không Scalaish.

Tôi nên làm gì? Nó không phải là một vấn đề khá phổ biến sao?

Trả lời

9

có điều này là một vấn đề khá thường xuyên, wha Tôi sẽ đề nghị là tạo ra một đặc điểm với tất cả các thuộc tính cha mẹ, tạo ra một lớp case chỉ thực hiện nó và sau đó một lớp khác thừa kế nó với nhiều thuộc tính hơn.

sealed trait Parent { 
    /* implement all common properties */ 
} 

case class A extends Parent 

case class B extends Parent { 
    /*add all stuff you want*/ 
} 

Cách tốt để xem đó là cây, đặc điểm là các nút và lớp chữ hoa.

Bạn có thể sử dụng một đặc điểm hoặc một lớp trừu tượng tùy thuộc vào nhu cầu của bạn cho phụ huynh. Tuy nhiên, tránh sử dụng một lớp bởi vì bạn sẽ có thể tạo ra các trường hợp của nó, mà sẽ không được thanh lịch.

EDIT: Như được đề xuất trong nhận xét, bạn có thể đóng dấu đặc điểm để có ngoại lệ khi biên dịch nếu không phải tất cả các kiểu chữ đều được bao phủ trong mẫu phù hợp. Ví dụ như được giải thích trong chương 15.5 của "Lập trình trong Scala"

+6

Niêm phong các đặc điểm cũng sẽ là một ý tưởng tốt. – agilesteel

3

tôi khám phá vấn đề này là tốt, AFAIK, tốt nhất bạn sẽ nhận được là:

Yêu cầu mỗi lớp trường hợp mở rộng từ một đặc điểm phổ biến mà định nghĩa trừu tượng tính mỗi lớp trường hợp phải thực hiện

Nó không loại bỏ bản mẫu (ở tất cả), nhưng định nghĩa một hợp đồng lớp trường hợp của bạn phải tuân theo, trong khi không mất trường hợp tính năng đẳng cấp bộ ...

6

Điều gì về việc thay thế thừa kế với ủy quyền?

Nếu hai lớp học của bạn trong hệ thống phân cấp có nhiều trường được chia sẻ thì ủy quyền có thể giảm số lượng mã bản mẫu? Cũng giống như vậy:

case class Something(aa: A, bb: B, cc: C, payload: Payload) 

sealed abstract class Payload 

case class PayloadX(xx: X) extends Payload 
case class PayloadY(yy: Y) extends Payload 

Và sau đó bạn sẽ tạo Something trường hợp như vậy:

val sth1 = Something('aa', 'bb', 'cc', PayloadX('xx')) 
val sth2 = Something('aa', 'bb', 'cc', PayloadY('yy')) 

Và bạn có thể làm mô hình kết hợp:

sth1 match { 
    case Something(_, _, _, PayloadX(_)) => ... 
    case Something(_, _, _, PayloadY(_)) => ... 
} 

Lợi ích: (?)

  • Khi bạn khai báo PayloadXPayloadY, bạn không phải lặp lại tất cả các lĩnh vực trong Something.

  • Khi bạn tạo các trường hợp Something(... Payload(..)), bạn có thể tái sử dụng mã tạo Something, cả khi bạn tạo một Something(... PayloadX(..))...PayloadY.

Nhược điểm: (?)

  • lẽ PayloadXY trong trường hợp của bạn là thực sự các lớp con thực sự của Something, ý tôi là, trong trường hợp của bạn, có lẽ đoàn là ngữ nghĩa sai?

  • Bạn sẽ phải viết something.payload.whatever thay vì chỉ đơn giản là something.whatever (Tôi cho rằng điều này có thể là tốt hay xấu tùy thuộc vào trường hợp cụ thể của bạn?)

+0

Một hạn chế khác: bạn sẽ không thể nói về các loại cụ thể trong các chữ ký phương thức nữa, nó sẽ luôn là "Cái gì đó". – Vituel

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