Java 最好改变父母';是字段还是覆盖getter?

Java 最好改变父母';是字段还是覆盖getter?,java,inheritance,overriding,Java,Inheritance,Overriding,假设我有一个投射物类,它作为游戏中所有投射物的基类。它包含最大速度、重力系数、反弹系数等的默认值 public abstract class Projectile { protected float maxSpeed = 100.0f; protected float gravityCoefficient = 1.0f; protected float bounceCoefficient = 1.0f; ... } 然后我有一堆子类,每个子类都可以选择覆盖其

假设我有一个
投射物
类,它作为游戏中所有投射物的基类。它包含最大速度、重力系数、反弹系数等的默认值

public abstract class Projectile {

    protected float maxSpeed = 100.0f;
    protected float gravityCoefficient = 1.0f;
    protected float bounceCoefficient = 1.0f;
    ...

}
然后我有一堆子类,每个子类都可以选择覆盖其中一些默认值

这里哪种方法更好

1。在子构造函数中设置字段值

public class Arrow {

    public Arrow(){
        super();
        maxSpeed = 200.0f;
    }

}
public class Arrow {

    public float getMaxSpeed(){
        return 200.0f;
    }

}
2。使子项覆盖getter

public class Arrow {

    public Arrow(){
        super();
        maxSpeed = 200.0f;
    }

}
public class Arrow {

    public float getMaxSpeed(){
        return 200.0f;
    }

}
我倾向于说第一种方法更好,因为它意味着可以直接访问字段,而不需要任何额外的函数调用。但是,这确实意味着该值在对象创建期间设置了两次,一次由父对象设置,一次由子对象设置


我有什么遗漏吗?也许还有其他方法吗?

第一种方法。在抽象基类中声明名为modifyDefaults()的方法。在每个类中实现它,并在构造函数中调用它,这样每当有人看到抽象类时,就可以断定您将修改子类中的默认值。

或者,如果只有几个决定性的参数,只需将创建射弹的责任移交给射弹工厂。

第一种方法。在抽象基类中声明名为modifyDefaults()的方法。在每个类中实现它,并在构造函数中调用它,这样每当有人看到抽象类时,就可以断定您将修改子类中的默认值。

或者,如果只有几个决定性的参数,就把创建投射物的责任交给投射物工厂。

对于java,编译器优化和JIT优化对于提高性能非常重要。

第二段代码将更易于优化,无需担心额外的操作。

对于java,编译器优化和JIT优化对于提高性能非常重要。

第二段代码将更易于优化,无需担心额外的操作。

您应该有一个setter并使用它,这就是setter的用途。它将允许您保持该字段的私密性。另一个好处是,使用JavaBean约定将允许您使用库来填充和操作对象。您还可以将数据持久保存在数据库或文件中

public abstract class Projectile {

    private float maxSpeed = 100.0f;  // default 

    protected void setMaxSpeed(float newSpeed) {
        maxSpeed = newSpeed;
    }
}

public class Arrow extends Projectile {

    public Arrow() {
        super();
        setMaxSpeed(200.0f);  // arrow specific values
    }
}

您应该有一个setter并使用它,这就是setter的用途。它将允许您保持该字段的私密性。另一个好处是,使用JavaBean约定将允许您使用库来填充和操作对象。您还可以将数据持久保存在数据库或文件中

public abstract class Projectile {

    private float maxSpeed = 100.0f;  // default 

    protected void setMaxSpeed(float newSpeed) {
        maxSpeed = newSpeed;
    }
}

public class Arrow extends Projectile {

    public Arrow() {
        super();
        setMaxSpeed(200.0f);  // arrow specific values
    }
}

你倾向于第一个答案应该是正确的。它明确规定了以下内容:

  • 子类负责创建自己的实例变量(属性)

  • 重写getter虽然在某些视图中听起来不错,但通常不会提供良好的可维护性。构造函数非常清楚地说明了额外的属性默认值集


我不确定你的设计,但是如果你的超类没有自己的状态,试着把它抽象化,这样设计就会比我们在这种情况下讨论的完全改变(当时可能会考虑选项2)。

你对第一个答案的倾向应该是。它明确规定了以下内容:

  • 子类负责创建自己的实例变量(属性)

  • 重写getter虽然在某些视图中听起来不错,但通常不会提供良好的可维护性。构造函数非常清楚地说明了额外的属性默认值集


我不确定你的设计,但是如果你有一个没有自己状态的超类,试着把它抽象化,这样设计就会比我们在这种情况下讨论的完全改变(当时可能会考虑选项2)。

直觉上,任何特定射弹的最大速度不可能在其使用寿命内发生变化(即使在同一类型的不同实例可能具有不同的最大速度的情况下),因此我倾向于为其设置一个最终字段。我也倾向于将其设置为最终值——除了真正的常量之外,我很少使用非私有字段

由于您对
射弹
有一些状态(字段),因此我将避免混淆
getMaxSpeed
显示的最大速度与字段不同

我可能会这样设计:

public abstract class Projectile {
    private final float maxSpeed;

    protected Projectile(float maxSpeed) {
        this.maxSpeed = maxSpeed;
    }

    // Only if you really need this...
    protected Projectile() {
        this(200f);
    }

    public final getMaxSpeed() {
        return maxSpeed;
    }
}

public class Arrow extends Projectile {
    public Arrow() {
        super(100f);
    }
}

重力系数和反弹系数可以以类似的方式处理-或者如果所有这些都真正充当“特定类型的每个实例的相同值”,则可以引入一个新类来表示这些常数,它将一个类型实例的变化状态与常量限制/系数分开,并且每个实例都可以有一个新类实例的最终引用。不幸的是,Java(以及至少一些类似的语言)并没有很好地对这种层次结构进行建模。这总是一个令人烦恼的问题:(

直觉上,任何特定射弹的最大速度不太可能在其使用寿命内发生变化(即使在相同类型的不同实例可能具有不同的最大速度的情况下),因此我倾向于为它设置一个最终字段。我也倾向于将其设置为最终字段-除了真正的常量之外,我很少使用非私有字段

由于您对
射弹
有一些状态(字段),因此我将避免混淆
getMaxSpeed
显示的最大速度与字段不同

我可能会这样设计:

public abstract class Projectile {
    private final float maxSpeed;

    protected Projectile(float maxSpeed) {
        this.maxSpeed = maxSpeed;
    }

    // Only if you really need this...
    protected Projectile() {
        this(200f);
    }

    public final getMaxSpeed() {
        return maxSpeed;
    }
}

public class Arrow extends Projectile {
    public Arrow() {
        super(100f);
    }
}
重力系数和反弹系数可以用类似的方式处理——或者,如果所有这些实际上都是“相同的