How do I validate a subclassed field in my Scala abstract parent object?
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 Ap开发者_JAVA百科iClient(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!
I think that the easiest solution is to make supportedContentTypes
in FacebookClient
lazy:
class FacebookClient(contentType: String) extends ApiClient(contentType) {
override lazy val supportedContentTypes = List("text/xml", "application/xml")
}
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
to def
and you are done.
精彩评论