【问题标题】:Java confusion with parameter passing in constructorsJava与构造函数中的参数传递混淆
【发布时间】:2015-09-04 01:31:32
【问题描述】:

我正在创建一个 BMR 计算器,并且我有一个名为 User 的类。该类包含用于计算 BMR 的所有方法,以及将用户数据(年龄、性别、体重、身高)打包在一起的构造函数。

代码是:

public class User {

int age;
String gender; // todo: use an Enum
double height; // height stored in cm, weight in kg (so if user enters in feet/lbs, conversions are done to cm/kg and *THEN* passed through to constructor below)
double weight;
double activityMultiplier; // todo: use an Enum  (possibly)
int bmr;


public User(int age, String gender, double height, double weight,
    double activityMultiplier) {
    this.age = age;
    this.gender = gender;
    this.height = height;
    this.weight = weight;
    this.activityMultiplier = activityMultiplier;

    bmr = calcBMR();
}

/**
 * If user input is correct, this method will calculate the BMR value of the user given their input and measurement choices.
 * 
 * @param None
 * @return BMR Value
 */
public int calcBMR() {
    int offset = gender.equals("M") ? 5 : -161;
    // This is the body of the calculations - different offset used depending on gender. Conversions to kg and cm done earlier so no conversions needed here.
    // The formula for male and female is similar - only the offset is different.
    return (int) (Math.round((10 * weight) + (6.25 * height) - (5 * age) + offset)); // This is the Miffin St-Jeor formula, calculations done in cm/kg
    }

/**
 * If the user selects the TDEE option, this method will be executed after the calcBMR() method. 
 * A value from the calcBMR() method will be passed down to this method, and is multiplied
 * by the activity level parameter passed into this method.
 * 
 * @param bmr (output from calcBMR() method
 * @return TDEE Value
 */
public int calcTDEE(int bmr) {
    return (int) Math.round(calcBMR() * activityMultiplier);
}

}

我担心的是我不确定我在构造函数 (bmr = calcBMR()) 中初始化 bmr 值的方式是否正确。我无法计算 bmr,直到用户的年龄、性别、身高和体重被记录并存储在变量中(这是上面 5 行所做的)。这种编程结构好吗? IE。当一个 User 对象被创建时,年龄、性别、身高和体重被存储在变量中,THEN在构造函数中调用一个方法来计算和存储另一个值。

有没有更好的方法来做到这一点?如果没有,我需要做this.bmr = calcBMR() 还是bmr = calcBMR() 可以吗?

请注意,用户对象是在单独的类中创建的。我主要困惑的原因是因为我没有将 bmr 参数传递给构造函数,而是使用方法返回值来初始化实例变量的值。

【问题讨论】:

    标签: java variables constructor


    【解决方案1】:

    语法上没问题,但是您不应该从构造函数中调用可覆盖(公共/受保护的非最终)方法。如果有人覆盖它,它可能会弄乱您的对象的构造。从构造函数调用辅助方法很好,只需将其设为私有或最终。

    this.bmr = calcBMR()bmr = calcBMR()

    bmr.calcBMR() 没有意义,因为calcBMR 方法在User 对象上。 bmr 是一个 int,所以它没有名为 calcBMR 的方法

    是否使用this 取决于您的喜好。只有当你有一个名为 bmr 的局部变量,然后你显式调用实例变量而不是本地变量时,它才会真正有所作为。通常,具有相同名称的局部变量和实例变量会令人困惑。

    你的calcTDEE 方法有点不对劲。你可以只使用bmr的值,而不是传入或重新计算它,所以它会是

    public int calcTDEE() {
        return (int) Math.round(bmr * activityMultiplier);
    }
    

    【讨论】:

    • 感谢您的评论。抱歉,当我写bmr.CalcBMR() 时,我的意思是bmr = calcBMR。编辑了我的帖子。因此,您提出的唯一建议是将calcBMR() 方法设为最终方法?这到底是做什么的?
    • 或者更有可能,如果您只是从课堂内部调用它,则将其设为私有。通过使其成为最终的或私有的,这意味着没有其他人可以改变它的行为。您可以创建一个覆盖 calcBMR() 的子类,然后可以更改您的计算(假设您不希望这样)。您也可以将其设为私有,然后使用 getBMR() 方法让人们获取价值。我假设您实际上并不希望人们调用 calcBMR(),您只是希望他们获得值,对吗?
    • 是的,没错。我自己调用calcBMR()的唯一地方是在构造函数中,主类只是创建了一个名为user1的User对象,并将bmr称为user1.bmr。我会将这个方法设为私有,因为它只从 User 类中调用,听起来不错?谢谢:)
    • 事实上,我把它留给了public,但改成了final,所以如果我需要修改代码,我仍然可以从BmrMain 类中调用它。将 final 添加到方法签名是否足够可行以使其不可覆盖?
    • 除了 Jeff 的优点之外,我建议您将所有字段设为私有并为每个字段提供 getter 方法。如果没有这个,外部代码可能会在不重新计算 bmr 的情况下更改某些字段值。
    【解决方案2】:

    我认为你的方式还可以。但是,如果您使用所有属性都是“私有的”并为它们设置 get/set 会更好。所以,当另一个类扩展你的类时,我们不必担心乱七八糟的事情。使用 calcTDEE 方法,我认为您只需将 bmr 属性放入其中,因为它是在构造函数中设置的。因此,在您调用此方法时,bmr 具有正确的值。

    public int calcTDEE() {
        return (int) Math.round(bmr * activityMultiplier);
    }
    

    希望对您有所帮助。

    【讨论】:

    • 我将研究使用 getter 和 setter 并将变量设为私有,尽管我不太热衷于使用它们。我已将我的 calcTDEE() 方法更改为您的建议,感谢您的回复:)
    【解决方案3】:

    最好将计算与构造分开。

    我个人认为我们应该避免这样做。根据我的说法,任何使用Class 的人正在构造你的Object 将不知道bmr 通过看到这个特定的构造函数也在User 中计算,直到他查看代码。当您构建API 时,您应该使其对将使用您的User 的消费者更具可读性,除此之外它是完全有效的。此外,正如Jeff Storey 所建议的,如果您不希望用户Objects 使用您的calcBMR,您应该将其设为private

    我想在这里补充一点,bmrPersonHealth 相关参数之一,因此您应该将所有此类参数收集在单独的类中,其中可以包括bodyFat、@987654336 @、medicalAge 等,并在此 class 的构造函数中传递您的 User Object。所以,最终Health参数只能由有效用户构造。

    【讨论】:

    • 我喜欢这个建议,但我还没有准备好做体脂计算器等。我想当我添加更多选项时,我会将基础知识存储在 User 类中,然后创建另一个类它可以包含计算 BMR、TDEE、体脂、宏(?)等的所有方法,以及可以存储值的构造函数。这是你想说的吗?
    • 好的,您认为最好的方法是从User 类的构造函数中调用Health 类的方法(即calcBodyFat()calcBMR())吗?
    • 好的,谢谢,所以我相信我现在拥有的方式(假设我没有添加更多功能,只是整理我当前的代码)很好 - 即在构造函数中调用方法.
    猜你喜欢
    • 1970-01-01
    • 2018-04-01
    • 2014-01-13
    • 2017-09-11
    • 2014-09-20
    • 1970-01-01
    • 2017-11-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多