我正在写一个消息解析器。假设我有一个带有两个辅助构造函数的超类Message
,一个接受String
原始消息,另一个接受Map
,其中数据字段以键值对映射。
class Message {
def this(s: String)
def this(m: Map[String, String])
def toRaw = { ... } # call third party lib to return the generated msg
def map # call third party lib to return the parsed message
def something1 # something common for all messages which would be overriden in child classes
def something2 # something common for all messages which would be overriden in child classes
...
}
有很好的理由这样做,因为解析/生成的库有点尴尬,并且删除与它连接成一个单独的类的复杂性是有意义的,子类看起来像这样:< / p>
class SomeMessage extends Message {
def something1 # ...
def something2 # ...
}
并且想法是在子类中使用重载的构造函数,例如:
val msg = new SomeMessage(rawMessage) # or
val msg = new SomeMessage("fld1" -> ".....", "fld2" -> "....")
# and then be able to call
msg.something1
msg.something2 # ...
然而,辅助构造函数和继承似乎在Scala中的行为方式已经证明这种模式非常具有挑战性,我到目前为止找到的最简单的解决方案是创建一个名为constructMe
的方法,它完成了上述案例中的构造函数:
val msg = new SomeMessage
msg.constructMe(rawMessage) # or
msg.constructMe("fld1" -> ".....", "fld2" -> "....")
这似乎很疯狂,需要一个名为constructMe
的方法。
所以,问题是:
有没有一种方法来构造代码,以便简单地使用超类中的重载构造函数?例如:
val msg = new SomeMessage(rawMessage) # or
val msg = new SomeMessage("fld1" -> ".....", "fld2" -> "....")
或者我只是以错误的方式解决问题?
答案 0 :(得分:1)
除非我遗漏了某些内容,否则你正在调用构造函数:
val msg = new SomeMessage(rawMessage)
但是Message
类没有参数,你的类应该这样定义:
class Message(val message: String) {
def this(m: Map[String, String]) = this("some value from mapping")
}
另请注意,scala中的构造函数必须将主构造函数作为第一个操作调用see this question for more info.
然后扩展Message
类的类应该是这样的:
class SomeMessage(val someString: String) extends Message(someString) {
def this(m: Map[String, String]) = this("this is a SomeMessage")
}
请注意,构造函数需要一个代码块,否则您的代码无法编译,您无法提供def this(someString: String)
之类的定义而无需提供实现。
编辑:
说实话,我不明白为什么你要在你的架构中使用Map
,你的班级主要指出它包含String
,与复杂类型有关构造函数可能导致问题。我们假设你有一些类可以将Map[String, String]
作为构造函数参数,你会用它做什么?正如我所说,构造函数必须将自己称为第一条指令,你可能会这样:
class A(someString: String) = {
def this(map: Map[String, String]) = this(map.toString)
}
就是这样,scala中的限制不允许你做更多的事情,你会想要做一些验证,比如让我们说你想要总是第二次在地图中的元素,这可能会抛出异常,因为用户不会被迫提供具有多个值的地图,除非您开始使用require
填充您的课程,否则他甚至不会被迫提供填充的地图秒。
在您的情况下,我可能会将String
作为类参数或List[String]
,您可以在其中调用mkString
或toString
。
无论如何,如果你对调用map.toString
感到满意,你必须将构造函数实现给父类和子类,这是scala构造函数限制之一(在Java中你可以用不同的方式解决问题),我希望有人会证明我错了,但据我所知,没有别的办法可以做到。
作为旁注,我个人觉得这种限制是正确的(大多数时候),因为你强迫你构建你的代码更加严谨并拥有更好的架构,考虑允许人们这样做的事实在构造函数中做任何他们想做的事情(比如在java中)混淆了他们的真正目的,那就是返回一个类的新实例。