簡體   English   中英

我應該使用靜態還是實例方法?

[英]Should I be using static or instance methods?

我真的對靜態vs實例方法的概念感到困惑。 我創建了一個BMR計算器。 我已經使用不同的類從計算中分離了GUI。

public class Calculations {

/**
 * If user input is correct, this method will calculate the BMR value of the user given their input and measurement choices.
 * 
 * @param userAge, userHeight, userWeight
 * @return BMR Value as a string
 */
public static int calcBMR(int age, String gender, double height, double weight) {

    // This is the body of the calculations - different formulas used depending on gender. Conversions to kg and cm done earlier so no conversions needed here.
    if (gender.equals("M")) { // Uses male bmr formula if genderMale radiobutton is selected
        return (int) (Math.round((10 * weight) + (6.25 * height) - (5 * age) + 5)); // This is the Miffin St-Jeor formula, calculations done in cm/kg
    } else { // else gender.equals("F") - there are only 2 options for gender, M or F.
        return (int) (Math.round((10 * weight) + (6.25 * height) - (5 * age) - 161));
    }
}


/**
 * 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 selectedActivityLevel
 * @return TDEE Value (as a string)
 */
public static int calcTDEE(double activityMultiplier, int bmr) {
    System.out.println(activityMultiplier);
    return (int) Math.round(bmr * activityMultiplier);
}

}

如您所見,這些方法是STATIC,但是傳遞給兩個方法的變量都是實例變量。

我只是通過以下幾行調用這些方法:

            bmrValue = Calculations.calcBMR(userAge, userGender, userHeight, userWeight);
            bmrLabel.setText("<html><br /><font size=4>You have a <i><font color=#ce0000>BMR</font></i> of: " + "<font color=#59AF0E>" +  bmrValue + "</font></html>");
            if (tdeeYes.isSelected()) {
                userActivityLevel = activityMap.get(activityLevelBox.getSelectedItem());
                // Looks up selected item from combo box, which is the KEY. Then looks up the value to this key from the map - this value is the TDEE multiplier.
                tdeeLabel.setText("<html><br /><font size=4>You have a <i><font color=#ce0000>TDEE</font></i> of: " + "<font color=#59AF0E>" + Calculations.calcTDEE(userActivityLevel, bmrValue) + "</font></html>");
                }

變量定義為:

HashMap<String, Double> activityMap;
String[] activityLevels = {"Sedentary", "Lightly Active", "Moderately Active", "Very Active", "Extra Active"};


int userAge;
String userGender;
double userHeight;
double userWeight;
double userActivityLevel;

int bmrValue;

我正確使用靜態/實例變量嗎? 之前我將所有參數變量都設置為靜態,因為我知道靜態方法只能訪問靜態變量。 直到現在我還不知道參數可能是實例變量。

任何指導將不勝感激。

對於初學者來說,靜態變量和實例變量之間的區別在於,對於類的所有實例,只存在一個靜態變量,而對於該類的每個實例都存在一個實例變量。

現在,當您談論方法時,在大多數情況下,當您嘗試從另一個靜態方法(例如main)調用方法時,您需要使方法成為靜態方法。

一般來說,這種做法對於OOP來說是錯誤的,你可能應該重新考慮程序的結構方式。

如果您可以提供有關用於調用這些方法的代碼的更多詳細信息,我將能夠幫助您了解有關如何解決此問題的更多詳細信息。

編輯:根據您提供的新信息:

1)我相信bmrMain,BMRMain和Calculations都可以合並為一個類。 應該調整新類的構造函數以讀取輸入(以及每個變量的getter和setter以增加靈活性 - 可選)

2)關於bmr部分的計算,有很多方法可以解決這個問題,因此我將繼續提出我認為最好的方法。 添加一個帶有文本“Click to calculate”或類似內容的Button,並實現一個ActionListener。 監聽器將依次調用(無論何時單擊按鈕)計算所有內容的方法,最后它將更改JLabel上的文本。

動作監聽器的示例代碼:

JButton button = new JButton("Text Button");
button.addActionListener(new ActionListener()
{
  public void actionPerformed(ActionEvent e)
  {
    //Call the methods for the calculation
    // bmr and tdee are temporary variables to store the results from the methods
    //handle them properly, or remove them if not needed (I just wrote a sample)
    int bmr = calcBMR(...); //pass the correct variables as arguments here
    int tdee;
    if(userHasPickedTDEE) {  tdee = calcTDEE(...); }  //and here
    label.setText(....);

  }
}); 

這兩個步驟將解決您的“靜態”問題。

我建議您對事件驅動編程進行一些研究

這里有一些關於動作聽眾的額外和更深入的閱讀

如果您需要進一步的幫助或澄清,請告訴我:)

EDIT2:

通常,是的,為了保持代碼的可管理性,將類分開是一個好習慣。 但在這種情況下,我認為僅為2種方法創建一個新類有點多余。 然而,如果您想保留當前結構,修復“靜態”的方法是:1)從2種計算方法中刪除靜態。 2)應該是332行

Calculations c = new Calculations();
bmrValue = c.calcBMR(userAge, userGender, userHeight, userWeight);

FINAL_EDIT:

好吧,這些問題很容易轉移到自己的線程中。 但是這里有一個有用的鏈接來自我剛剛做的快速谷歌搜索,這將有助於破壞靜態關鍵字:

Java中的靜態關鍵字

我使用靜態變量的拇指規則有點像這樣:

  1. 不要使用static
  2. 當需要使用static參考(1)

對於大多數情況,上述拇指規則有效。 但是,我們有JDK,apache-commons庫推廣的標准習語。 調查它們你會發現:

  1. 可以使用包含所有靜態方法的實用程序類。
  2. 可以使用類中的static字段創建常量。 雖然,對於這個使用Enum可能是一個更好的選擇。
  3. 一個關閉實用程序函數可以在同一個類上工作。

至於代碼的重組,你應該看看誰擁有這些數據。 在這種情況下,來自Calculations類的兩個方法都使用來自另一個類的數據。 將方法移動到另一個類中。

存在Calculations類的唯一原因應該是,如果您使用來自多個其他不相關的類的方法。 如果它們是相關的,那么您可以嘗試建模它們之間的關系並查看這些方法的位置。

每當我的類被用來調用那些方法時我都會使用static(即我的main方法調用靜態方法在主類中設置變量等)。 我相信這是KDM提到的“實用”類。 我使用靜態或實用程序類的一個小例子:

class Utility {
  public static int add(int a, int b) {
    // You would, of course, put something besides simple addition here
    return a + b;
  }
}

class Main {
  public static void main(String[] args) {
    int a = 2, b = 3;
    int sum = Utility.add(a, b);
    System.out.println(sum);
  }
}

另一方面,如果您有一個更接近實際對象的類,並且具有自己的屬性,請遠離靜態。 如果使用static,那么您希望作為單獨對象的類的每個實例將以相同的值結束。

根據您的類的名稱和功能,您似乎有一個實用程序類。 靜態應該沒問題,但可能沒有必要。 但是,假設你想將這個類用於多個“人”類實例來計算BMR(每個實例都是唯一的),那么我會將calcBMR()放在一個person類中並使其非靜態,所以每個人都有自己的calcBMR()

編輯:也許這也會有所幫助:

Instance - > Instantiate: new Calculations().instanceMethod();

靜態 - >類本身,類的“狀態”: Calculations.staticMethod();

如果你想的是,我想要實例方法還是靜態方法,你就會迷失方向。 Java不是面向方法的,而是面向對象的。 因此,為了您的功能,決定您是否需要一個對象或一個純函數(純函數意味着沒有依賴性和沒有副作用,它嚴格來說是一個函數,給出這個返回)。

將此建模為對象可能會很好,因為您有描述用戶某些方面的信息,將它們保持在一起可能是有意義的:

public class User {
    private int age;
    private String gender; // todo: use an Enum
    private double height;
    private double weight;
    private String activityLevel; // todo: use an Enum

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

    public double calculateBmr() {
        int offset = gender.equals("M") ? 5 : -161;
        return (int) (Math.round((10 * weight) 
            + (6.25 * height) - (5 * age) + offset));
    }
}

這樣我們就不必在變量前加上“user”,它們都放在一個對象中。 對象是用於收集相關信息的組織方案,實例方法是使用對象信息的函數。

替代路線是創建實用程序類:

public final class UserCalcUtil {
    private UserCalcUtil() {} // no point instantiating this

    public static int calculateBmr(String gender, double height, 
    double weight, int age) {
        int offset = gender.equals("M") ? 5 : -161;
        return (int) (Math.round((10 * weight) 
            + (6.25 * height) - (5 * age) + offset));            
    }
}

在這里,您將分別跟蹤用戶數據,並在您想要計算某些內容時將其傳遞給靜態方法。 實用程序類是單獨的靜態方法(您可以將其視為函數)的轉儲點。

是否要使用對象或實用程序類取決於您希望如何組織數據並對其進行計算。 如果您始終對單個對象進行計算,或者將計算移動到實用程序類中,如果您需要多個不相關的類,那么將用戶的數據與對該數據起作用的方法一起打包可能會更方便做計算。 由於Java對面向對象的構造有更多的支持,因此采用對象方法通常是有意義的。

你可以使用靜態方法,但是除了常量之外的任何東西都要避免使用靜態變量(public static final,其類型是不可變的)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM