3 回答
TA贡献1906条经验 获得超3个赞
您不应该从构造函数中调用 getter 和 setter。
构造函数构造定义它的特定类。初始化字段是它的工作,因为 - 好吧 - 没有其他东西可以。
保证初始化字段的唯一方法是分配它们。如果您调用 setter,则它可能会被覆盖,并且可能会执行其他操作。它可能会调用尚未初始化的子类中的方法。
如果您只是从同一个类中获取一个字段,那么调用 getter 也是一个坏主意。如果它已在超类中声明,您可能会证明它是合理的;如果您需要在子类中从超类获取数据,则必须调用 getter(除非它受到保护)。如果您需要在构建过程中将数据从子类传递到超类,则应将其作为参数传递。但这与您所描述的用例不同,并且子类可能无论如何都没有您自己的与 getter 对应的字段。
如果您有任何“特殊”初始化代码,请将其放在单独的私有方法中,并分别从构造函数和 setter 调用它。
TA贡献1796条经验 获得超10个赞
这取决于,你是否打算继承这个类,其他人应该能够继承你的类吗?
如果答案是否定的,那么您可以使用它,但我会说这样做通常是不好的做法,原因有几个,如果您没有明确禁止继承,那么可以对类进行子类化并重写方法,请参见下面的引用。一般来说,最好的做法是尽可能多地实现不变性,并且使用 getter/setter 可以防止你这样做。我还认为构造函数应该只具有将类初始化为有效状态所必需的参数。如果它们也可以使用 setter 传递,那么它们可能不是实现有效状态所必需的。
如果你想在设计类时考虑到继承,那么答案是否定的,如果你使用 init 方法,它也不能使用 getter/setter,或者任何可以被覆盖的方法。来自 Effective Java 2nd Edition 的直接引用:
一个类必须遵守更多的限制以允许继承。构造函数不得直接或间接调用可覆盖的方法。如果您违反此规则,将导致程序失败。超类构造函数在子类构造函数之前运行,因此子类中的覆盖方法将在子类构造函数运行之前被调用。如果覆盖方法依赖于子类构造函数执行的任何初始化,则该方法将不会按预期运行。
TA贡献1853条经验 获得超6个赞
我看到的方式是,当构造函数定义类时,我可以使用 setter 来检查参数和/或将它们初始化为某些值。在我有一个计算变量的情况下,我也可以使用 getter,但我应该非常小心语句的顺序(不建议容易出错)。
JavaScript 中的示例:
class Point {
constructor (x, y) {
this.x = x.x || x // invokes the setter
this.y = x.y || y
}
toString () {
return `The point is (${this.x}, ${this.y})` // invokes the getters
}
set x (newX) { // I think it should be better use 'newX' as a parameter than 'x'
if (newX > 100) {
console.log(`The x (${newX}) value must be < 100, `, 'x set to 0')
this._x = 0 // if we use 'this.x' here, we will get an error (stack overflow)
return
}
this._x = newX
}
get x () { // no one but the getter and setter should know '_x' exists
return this._x // it has to be coherent with the setter
}
set y (newY) {
if (newY > 100) {
console.log(`The y (${newY}) value must be < 100, `, 'y set to 0')
this._y = 0
return
}
this._y = newY
}
get y () {
return this._y
}
}
添加回答
举报