2013-06-12 68 views
2

假設我想在Scala中表示Book,並且它是直接從XML生成的。 我想要一個包裝父類XMLObject包含可以直接映射到XML和從XML映射的類。在Scala中重寫和繼承的次級構造函數

下面是這個工作實施的例子,但我想知道爲什麼構造函數不能是抽象的,你不能使用override關鍵字,但你仍然可以重新定義構造函數具有相同簽名爲父類在子類中,並且按照您期望的方式工作。

這是否被認爲是「不好」的編碼實踐,如果是這樣,那麼獲得類似功能的更好方法是什麼?

abstract class XMLObject { 
    def toXML:Node 
    def this(xml:Node) = this() 
} 

class Book(

    val author:String = "", 
    val title:String = "", 
    val genre:String = "", 
    val price:Double = 0, 
    val publishDate:Date = null, 
    val description:String = "", 
    val id:Int = 0 

) extends XMLObject { 

    override def toXML:Node = 
    <book id="{id}"> 
     ... 
    </book> 

    def this(xml:Node) = { 
    this(
     author = (xml \ "author").text, 
     title = (xml \ "title").text, 
     genre = (xml \ "genre").text, 
     price = (xml \ "price").text.toDouble, 
     publishDate = (new SimpleDateFormat("yyyy-MM-dd")).parse((xml \ "publish_date").text), 
     description = (xml \ "description").text 
    ) 
    } 
} 

使用例:

val book = new Book(someXMLNode) 

回答

1

構造函數只能在形式被稱爲:

new X(...) 

這意味着你知道你要創建的對象的運行時類型。意義重寫在這裏沒有意義。例如,您仍然可以在抽象類中定義構造函數,但這是爲了鏈接(在類構造函數中調用超類構造函數)。

你似乎在尋找什麼,而一個工廠模式:

  1. XMLObject
  2. 刪除構造函數如果你想添加一個功能,其判定基於XML你XMLObject的伴侶傳入,創建什麼子類。

例如:

object XMLObject { 
    def apply(xml: Node) = xml match { 
    case <book> _ </book> => new Book(xml) 
    // ... 
    case _ => sys.error("malformed element") 
    } 
} 
1

我會用型類此。

您希望能夠將書(和其他東西)映射到XML和從XML映射的事實與這些實體的正交。您不希望僅基於您希望這些對象具有一些共同的XML映射功能這一事實來選擇類層次結構。 Book的適當超類可能是PublishedEntity或類似的東西,但不是XMLObject。

如果下週要添加JSON解析/呈現,會發生什麼?您已經使用XML的超類;你會怎麼做?

更好的解決方案是爲XML接口創建一個特徵並將其混入到根中。這樣你就可以混合儘可能多的這種東西,並且仍然可以自由選擇合理的類層次結構。

但是更好的解決方案是類型類,因爲它們允許你添加對別人類的支持,你不能添加方法。

這裏是a slide presentation that Erik Osheim prepared on type classes

許多JSON解析器/格式化程序包(例如Spray's)都使用類型類。我沒有在Scala中使用太多的XML,但我猜想也有XML的類型實現。快速搜索出現了this