凌驾&;Scala中继承的二级构造函数

凌驾&;Scala中继承的二级构造函数,scala,inheritance,constructor,coding-style,Scala,Inheritance,Constructor,Coding Style,假设我想用Scala表示一本书,它是直接从XML生成的。 我需要一个包装父类XMLObject,以包含可以直接映射到XML和从XML映射到XML的类 下面是一个工作实现的示例,但我想知道为什么构造函数不能是抽象的,并且不能使用override关键字,但是您仍然可以在子类中重新定义一个与其父类具有相同签名的构造函数,并让它按照您期望的方式工作 这被认为是“糟糕”的编码实践吗?如果是,那么获得类似功能的更好方法是什么 abstract class XMLObject { def toXML:No

假设我想用Scala表示一本
书,它是直接从XML生成的。
我需要一个包装父类
XMLObject
,以包含可以直接映射到XML和从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
    )
  }
}

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

new X(...)
这意味着您知道要创建的对象的运行时类型。这里的意思是覆盖没有意义。例如,您仍然可以在抽象类中定义构造函数,但这是用于链接的(在类构造函数中调用超类构造函数)

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

  • XMLObject
  • 如果需要,可以在
    XMLObject
    的同伴中添加一个函数,该函数根据传入的XML决定要创建的子类
  • 例如:

    object XMLObject {
      def apply(xml: Node) = xml match {
        case <book> _ </book> => new Book(xml)
        // ...
        case _ => sys.error("malformed element")
      }
    }
    
    objectxmlobject{
    def apply(xml:Node)=xml匹配{
    案例=>新书(xml)
    // ...
    大小写=>sys.error(“格式错误的元素”)
    }
    }
    
    我会为此使用类型类

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

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

    更好的解决方案是为XML接口创建一个特性,并将其从根目录中混合。通过这种方式,您可以混合任意多的内容,并且仍然可以自由选择合理的类层次结构

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

    这是

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

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