如何验证 Scala 抽象父对象中的子类字段?
我相信在 Scala 中,就像在 Java 中一样,子类字段在超级构造函数执行后初始化。鉴于此,我正在努力确定如何最好地创建“抽象字段”,这些字段可以在我的子类中初始化,但在我的抽象父类的构造函数中进行验证(或用于验证其他字段)。举一个不起作用的简单例子:
abstract class ApiClient(contentType: String) {
val supportedContentTypes: List[String]
if (!(supportedContentTypes contains contentType)) {
throw new RuntimeException("Type " + contentType + " not supported")
}
}
class FacebookClient(contentType: String) extends ApiClient(contentType) {
override val supportedContentTypes = List("text/xml", "application/xml")
}
val api = new FacebookClient("text/xml") // Throws NullPointerException
这个问题在 Java 中被广泛讨论(例如 这里和这里),一般答案是把父类构造函数中的“抽象字段”。这个建议也适用于 Scala,还是我缺少一个更简洁的替代方案?
要在 Scala 中遵循这种方法,我的代码将如下所示:
abstract class ApiClient(contentType: String, supportedContentTypes: List[String]) {
if (!(supportedContentTypes contains contentType)) {
throw new RuntimeException("Type " + contentType + " not supported")
}
}
class FacebookClient(contentType: String) extends ApiClient(
contentType,
List("text/xml", "application/xml")) {
}
val api = new FacebookClient("text/xml") // Runs!
这是最好的方法吗?我还没有看到任何相反的例子,但是像这样加载超级构造函数对我来说“闻起来”不太好。任何想法都感激不尽!
I believe that in Scala, like in Java, subclass fields are initialized after the super constructor has executed. Given this, I'm struggling to identify how best to create "abstract fields" that can be initialized in my subclass but validated (or used for validation of other fields) in the constructor of my abstract parent class. To give a simple example of what doesn't work:
abstract class ApiClient(contentType: String) {
val supportedContentTypes: List[String]
if (!(supportedContentTypes contains contentType)) {
throw new RuntimeException("Type " + contentType + " not supported")
}
}
class FacebookClient(contentType: String) extends ApiClient(contentType) {
override val supportedContentTypes = List("text/xml", "application/xml")
}
val api = new FacebookClient("text/xml") // Throws NullPointerException
This question is much-discussed for Java (e.g. here and here) and the general answer is to put the "abstract fields" in the parent class's constructor. Does this advice hold true for Scala too, or is there a neater alternative I'm missing?
To follow this approach with Scala, my code would look like this:
abstract class ApiClient(contentType: String, supportedContentTypes: List[String]) {
if (!(supportedContentTypes contains contentType)) {
throw new RuntimeException("Type " + contentType + " not supported")
}
}
class FacebookClient(contentType: String) extends ApiClient(
contentType,
List("text/xml", "application/xml")) {
}
val api = new FacebookClient("text/xml") // Runs!
Is this the best approach? I haven't seen any examples to the contrary but loading up the super constructor like this doesn't "smell" great to me. Any thoughts gratefully received!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我认为最简单的解决方案是使
FacebookClient
中的supportedContentTypes
变得懒惰:这应该按预期工作。
您还可以使用抽象方法 - 它也应该可以正常工作。但与 Java 相比,涉及的语法要少得多。您通常需要将
val
更改为def
就完成了。I think that the easiest solution is to make
supportedContentTypes
inFacebookClient
lazy:This should work as expected.
You can also use abstract method - it should also work just fine. But in contrast to Java, much less syntax is involved. You generally need to change
val
todef
and you are done.