2

假设我想Book在 Scala 中表示 a,它是直接从 XML 生成的。我想要一个包装父类XMLObject来包含可以直接映射到 XML 和从 XML 映射的类。

下面是一个工作实现的例子,但我想知道为什么构造函数不能是抽象的,你不能使用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)
4

2 回答 2

1

构造函数只能以以下形式调用:

new X(...)

这意味着您知道要创建的对象的运行时类型。意义压倒在这里毫无意义。例如,您仍然可以在抽象类中定义构造函数,但这是用于链接(在类构造函数中调用超类构造函数)。

您似乎正在寻找的是一种工厂模式:

  1. 删除构造函数XMLObject
  2. 如果您愿意,可以向XMLObject' 的伙伴添加一个函数,该函数根据您传入的 XML 来决定要创建的子类。

例如:

object XMLObject {
  def apply(xml: Node) = xml match {
    case <book> _ </book> => new Book(xml)
    // ...
    case _ => sys.error("malformed element")
  }
}
于 2013-06-12T18:42:31.183 回答
1

我会为此使用类型类。

您希望能够将 Book(和其他东西)映射到 XML 和从 XML 映射出的事实与这些实体是正交。您不希望仅仅基于您希望这些对象具有一些共同的 XML 映射功能这一事实来选择类层次结构。Book 的适当超类可能是 PublishedEntity 或类似的东西,但不是 XMLObject。

如果下周你想添加 JSON 解析/渲染会发生什么?您已经使用了 XML 的超类;你会怎么做?

更好的解决方案是为 XML 接口创建一个特征并将其混入根目录。这样,您可以根据需要混合任意数量的此类内容,并且仍然可以自由选择合理的类层次结构。

但是更好的解决方案是类型类,因为它们允许您添加对其他人的类的支持,而您无法添加方法。

这是Erik Osheim 准备的关于类型类的幻灯片演示

许多 JSON 解析器/格式化程序包(例如 Spray 的)都使用类型类。我在 Scala 中没有过多地使用 XML,但我猜想 XML 也有类型类实现。快速搜索出现了这个

于 2013-06-13T17:13:00.503 回答