2012-05-18 31 views
15

我知道你不能從案例類繼承,但當你真的需要時你會怎麼做?我們在層次結構中有兩個類,都包含很多字段,我們需要能夠創建兩個類的實例。這是我的選擇:如何在需要層次結構時使用案例類?

  • 如果我會做超類常規類,而不是一個案例類 - 我會失去所有的情況下,類善良如toString,平等相待,hashCode方法等
  • 如果我把它作爲一個案例類,我打破了不從案例類繼承的規則。
  • 如果我在子類中使用組合 - 我必須寫很多方法並將它們重定向到其他類 - 這意味着很多工作,並且會感覺非Scalaish。

我該怎麼辦?這不是一個普遍的問題嗎?

回答

9

是的,這是一個相當經常出現的問題,世界衛生大會我建議創建一個包含所有父屬性的特徵,創建一個只是實現它的案例類,然後再創建一個具有更多屬性的案例類。

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

case class A extends Parent 

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

看到它的好方法是樹,特徵是節點,案例類是樹葉。

根據您對家長的需求,您可以使用特質或抽象類。但是,請避免使用類,因爲您可以創建它的實例,這不會很優雅。

編輯:正如評論所說,你可以密封的特點,以便如果不是所有情況下類覆蓋的模式匹配有在編譯例外。例如在「Scala編程」的第15.5章中進行了解釋

+6

密封的特質也將是一個不錯的主意。 – agilesteel

3

我探討過這個問題爲好,據我所知,你會得到最好的是:

讓每個案例類從定義抽象 性質每種情況下類必須實現

一個共同的特點延伸

它不會刪除樣板(的話),但是定義了一個合同的情況下類必須堅持,在不損失的情況下類的功能集...

6

如何用代理替換繼承?

如果你的兩個類層次結構中有很多共享字段,然後代表團可以減少樣板代碼是多少?像這樣:

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 

然後您可以創建Something情況下,像這樣:

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

你可以做模式匹配:

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

優點:(?)

  • 當你聲明PayloadXPayloadY,你不必重複所有字段東西

  • 當您創建的Something(... Payload(..))情況下,您可以重新創建Something代碼,無論是當你創建一個Something(... PayloadX(..))...PayloadY

缺點:(?)

  • 也許PayloadXY你的情況其實都是Something真子,我的意思是,你的情況,也許代表團語義錯了嗎?

  • 你會寫something.payload.whatever,而不是簡單something.whatever(我想這可能是好還是壞取決於你的具體情況?)

+0

另一個缺點:你不能在方法簽名中談論特定的類型,它將永遠是「某事」。 – Vituel