2012-09-05 170 views
8

我對Scala相當陌生,正在編寫一個API庫並嘗試僅使用vals和不可變對象(在可能的情況下)。我正在試圖以正確的方式來模擬對象。假設有幾個「郵報」的對象,都有着一些共同的領域,每一個增加自己的具體領域:Scala擴展參數化抽象類

abstract class Post(val id: Int, val name: String, ...) 
case class TextPost(val id: Int, val name: String, ..., val text: String) extends Post(id, name, ...) 
case class PhotoPost(val id: Int, val name: String, ..., val url: String) extends Post(id, name, ...) 

這種方法增加了很多重複的聲明和鍋爐板代碼,特別是有許多打交道時在抽象類中聲明Post子類和共享字段。我看到它的方式,這是由於val的使用,只能由構造函數初始化。有沒有更好的方法來創建這裏詳述的關係,還是我必須忍受這種情況只想使用不可變對象?

回答

8

首先,case-class構造函數中的val修飾符是多餘的,Scala編譯器將已經「免費」給它們(這是case-classes的一個特性)。如果你真的想編譯,你會看到,由於未申報壓倒一切的發生錯誤:

abstract class Post(val id: Int, val name: String) 
case class TextPost(id: Int, name: String) extends Post(id, name) 
case class PhotoPost(id: Int, name: String) extends Post(id, name) 

<console>:10: error: overriding value id in class Post of type Int; 
value id needs `override' modifier 
      case class PhotoPost(id: Int, name: String) extends Post(id, name) 
           ^

我個人建議使用抽象類與構造函數參數儘可能少。斯卡拉的特質在這裏做得更好。而不是構造函數參數,你聲明(抽象)字段;那麼case類在踢,並且由於它們自動使他們的論點vals,你做:

trait Post { def id: Int; def name: String } 
case class TextPost(id: Int, name: String, text: String) extends Post 
case class PhotoPost(id: Int, name: String, url: String) extends Post 

此外,如果添加sealedtrait Post,你可以放心地使用Post亞型的模式匹配,而不會意外失蹤案件。

+0

感謝您的回答!就鍋爐代碼而言,這種方法基本上可以省去我在派生類中將每個參數聲明爲val,但是我仍然必須在每個聲明中重複所有參數,對吧?我強調這一點,因爲我有8個子類和15個共享字段,這看起來像一個巨大的幹案。但我從你的回答中明白,這是沒有辦法解決的,對吧? – orrsella

+1

唯一的另一種選擇是不__實現通用接口('Post')。這意味着你需要_compose_類型來包含它,但我不知道這是你想要的:case class Post(id:Int,name:String); case class TextPost(post:Post,text:String)'。 –

+5

我不覺得這個答案是足夠的,因爲它不回答鍋爐板問題... –