是否可以在Scala构造函数中使用命名参数,稍后在不破坏构造函数接口或使代码非常难看的情况下覆盖getter和setter?
采取以下scala代码
class Person( var FirstName: String, var LastName: String )
干净整洁。这将创建一个名为person的简单类,我们可以按以下方式使用
val john = new Person( FirstName="John", LastName="Doe" )
john.FirstName = "Joe"
println( john.FirstName )
稍后,我们决定要为FirstName setter添加一些验证。因此,我们创建一个新的私有局部变量并覆盖getter和setter方法
class Person( var _FirstName: String, var _LastName: String ) {
def FirstName = _FirstName
def FirstName_= (value:String) = _FirstName = value
}
仍然有点干净,但是为了做到这一点,我们必须更改构造函数参数名称,从而打破外部接口。
我想出的第一个解决这个问题的方法是
class Person {
var _FirstName:String = null
var LastName:String = null
def FirstName = _FirstName
def FirstName_= (value:String) = _FirstName = value
def this( FirstName: String, LastName: String ){
this()
this._FirstName = FirstName
this.LastName = LastName
}
}
这有点丑陋和不优雅,并且删除了我首先使用scala的大部分原因。
有更好的方法吗?
tl; dr如何覆盖默认构造函数中定义的成员的getter / setter,而不会使代码变得丑陋或更改公共接口?
答案 0 :(得分:10)
您是否考虑过使用伴侣对象?
class Person private (f: String, l: String ) {
var FirstName = f
var LastName = l
}
object Person {
def apply(FirstName:String, LastName:String) =
new Person(FirstName, LastName)
}
答案 1 :(得分:5)
如果您尚未使用隐式转换来创建参数,则可以执行以下操作:
def validateName(s: String) = {
if (s.length>0 && s(0).isUpper) s
else throw new IllegalArgumentException(s+" is not a name!")
}
object Example {
private[Example] class ValidatedName(val s: String) { }
class Person(var firstName: ValidatedName, var lastName: String) { }
implicit def string2valid(s: String) = new ValidatedName(validateName(s))
implicit def valid2string(v: ValidatedName) = v.s
}
scala> new Example.Person("Joe","Schmoe")
res17: Example.Person = Example$Person@51887dd5
scala> new Example.Person("ee","cummings")
java.lang.IllegalArgumentException: ee is not a name!
它不是二进制兼容,但它是源兼容的(再次,如果名称还没有依赖隐式转换)。
另一个稍微长一点的可能性就是创造一个隐形祖先:
class CheckedPerson(private var first: String, var lastName: String) {
def firstName = first
def firstName_=(s: String) { first = validateName(s) }
}
class Person(firstName: String, lastName: String) extends
CheckedPerson(validateName(firstName),lastName) { }
我不确定二进制兼容性,但肯定会提供源兼容性。
答案 2 :(得分:4)
没有。目前没有办法做到这一点,它目前不是研究的重点。
这是我对语言的一个主要的烦恼:没有合理的方法来组合构造函数参数和自定义的getter / setter方法。
如果您对class Person( var FirstName: String, var LastName: String )
提供的功能不满意,它基本上意味着“回到Java的冗长”。