简体   繁体   English

更好地更改父母的领域或覆盖吸气剂?

[英]Better to change parent's field or override getter?

Let's say I have a Projectile class which acts as a base class for all projectiles in my game. 假设我有一个Projectile类,它充当游戏中所有弹丸的基类。 This contains default values for maximum speed, gravity coefficient, bounce coefficient, etc. 它包含最大速度,重力系数,反弹系数等的默认值。

public abstract class Projectile {

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

}

I then have a bunch of subclasses, each of which may choose to override some of these default values. 然后,我有一堆子类,每个子类都可以选择重写某些默认值。

Which is the better approach here? 哪种方法更好?

1. Set field values in child constructor 1.在子构造函数中设置字段值

public class Arrow {

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

}

2. Make child override getter 2.让孩子覆盖吸气剂

public class Arrow {

    public float getMaxSpeed(){
        return 200.0f;
    }

}

I am inclined to say that the first approach is better, since it means the field can be accessed directly without the need for any extra function calls. 我倾向于说第一种方法更好,因为这意味着可以直接访问该字段,而无需任何额外的函数调用。 However, it does mean that the value is set twice during object creation, once by the parent and once by the child. 但是,这确实意味着该值在对象创建期间设置了两次,一次由父级设置,一次由子级设置。

Am I missing anything here? 我在这里想念什么吗? Is there, perhaps, another approach? 也许还有另一种方法?

Intuitively, the maximum speed of any particular projectile is unlikely to vary over its lifetime (even in the case where different instances of the same type can have different maximum speeds), therefore I would favour a final field for it. 直观地讲,任何特定弹丸的最大速度在其生命周期内都不太可能发生变化(即使在相同类型的不同实例可以具有不同的最大速度的情况下),因此,我希望最终使用它。 I would also favour making it final - I very rarely use non-private fields, other than for genuine constants. 我也希望将其定型-除了真正的常量之外,我很少使用非私有字段。

As you have some state (the field) for Projectile , I would avoid allowing the confusion of having the maximum speed has revealed by getMaxSpeed differing from the field. 当您具有Projectile某些状态(字段)时,我将避免让getMaxSpeed揭示出与字段不同而导致的最大速度的混淆。

I would probably design it like this: 我可能会这样设计:

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);
    }
}

The gravity coefficient and bounce coefficient may be treated in a similar way - or if all of these really act as "the same values for every instance of a particular type" you could introduce a new class to represent these constants, which separates the varying state of instances of a type from the constant restrictions/coefficients - and each instance could just have a final reference to an instance of that new class. 可以用类似的方式来处理引力系数和弹跳系数-或如果所有这些真的都充当“对于特定类型的每个实例相同的值”,则可以引入一个新类来表示这些常数,从而将变化的状态分开从常量限制/系数中提取类型的实例-每个实例可能只是对该​​新类的实例的最终引用。 Unfortunately Java (and at least some similar languages) don't really model this kind of hierarchy well. 不幸的是,Java(以及至少一些类似的语言)并不能很好地模拟这种层次结构。 It's always an annoyance :( 总是很烦人:(

you should have a setter and use it, that is what setters are for. 您应该有一个二传手并使用它,这就是二传手的用途。 It will allow you to keep the field private. 它将允许您将字段保持私有状态。 The other benefit is that using Java Bean convention will allow you to use libraries such as Apache Commons BeanUtils to populate and manipulate your Objects. 另一个好处是,使用Java Bean约定将允许您使用诸如Apache Commons BeanUtils之类的库来填充和操作对象。 You will also be able to persist your data in DB or file. 您还可以将数据持久保存在数据库或文件中。

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
    }
}

First approach. 第一种方法。 Declare a method named modifyDefaults() in your abstract base class. 在抽象基类中声明一个名为ModifyDefaults()的方法。 Implement it in each class and call in the constructor so that whenever someone sees abstract class, it can be concluded that you will be modifying defaults in children. 在每个类中实现它并在构造函数中调用,以便每当有人看到抽象类时,都可以得出结论,您将修改子级中的默认值。
Or just hand over responsibility of Projectile creation to a projectileFactory if there are only a few deciding parameters. 或者,如果只有几个决定性参数,则只需将Projectile创建的职责移交给projectileFactory。

Your inclination towards the first answer should be. 您倾向于第一个答案。 It does clearly state the following: 它确实明确指出以下内容:

  • The child class has it's responsibility of creating it's own instance variables (properties) 子类负责创建自己的实例变量(属性)

  • Overriding of getter, though sounds good at certain views, doesn't usually give a good maintainability. 尽管在某些观点上听起来不错,但重写吸气剂通常不能提供良好的可维护性。 Constructor clearly states the extra set of property defaults whatsoever very cleanly. 构造函数很清楚地声明了额外的一组属性默认值。

I'm not sure about your design, but if you have your super class which doesn't have state of it's own, try making it abstract and the design changes completely than we discussed in that case (option 2 might be considered that time). 我不确定您的设计,但是如果您拥有的超类没有自己的状态,请尝试使其abstract ,并且设计会比我们在那种情况下所讨论的完全更改(那时候可以考虑选项2) 。

For java, compiler optimization and JIT optimization are of great importance for the improvement of performance. 对于Java,编译器优化和JIT优化对于提高性能非常重要。
The second piece of code will be much more easier to be optimized with no worry of extra operations. 第二段代码将更容易优化,无需担心额外的操作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM