簡體   English   中英

使用 getter 還是直接訪問私有成員更好?

[英]Is it better to use getters or to access private members directly?

以下哪個更好? 它甚至基於意見還是存在任何相關差異? 在某些情況下可以偏愛其中一個嗎?

public class MyClass {
    private Integer myField;

    public void setMyField(Integer myField) {
        this.myField = myField;
    }

    public Integer getMyField() {
        return myField;
    }

}

我需要一種方法來檢查是否允許某事。 請不要談論這個代碼示例的意義。 這只是一個最小的例子。

實施1

public boolean isAllowed() {
    MyEnum.ALLOWED.getInt().equals(getMyField());
}

實施2

public boolean isAllowed() {
    MyEnum.ALLOWED.getInt().equals(myField);
}

編輯:此帖子在鏈接的問題中沒有答案(請參閱對初始帖子的評論)

以下哪個更好? 它甚至基於意見還是存在任何相關差異? 在某些情況下可以偏愛其中一個嗎?

我認為這是良好實踐的問題。 區別在於代碼的可讀性。

作為一般規則,如果不需要,您應該避免間接。 MyClass的當前實例在這些字段之一中具有用於實現操作的信息。 它不需要向自己隱藏其內部狀態。
所以在內部, MyClass沒有有價值的理由支持使用getMyField()而不是直接使用myField字段。
getMyField()訪問器更適合類的客戶端使用。
所以我認為在您的示例代碼中無論如何都更好:

public boolean isAllowed() {
    MyEnum.ALLOWED.getInt().equals(myField);
}

編輯
除了可讀性之外,這里還有一個示例,說明為什么您沒有興趣將內部狀態耦合到公共 getter。
在開發階段,你從類中刪除假設public getMyField()方法,因為不再需要或為類的客戶沒有任何不再需要,如果isAllowed()依賴於getMyField()在執行,它會被打破,你應該用myField替換它。

我的答案不會是最有信息量的,但是它將來自處理這種模式的直接經驗。 在設計對象時,通常傾向於直接訪問成員字段而不是依賴訪問器。 這個願望源於想要簡化對象並避免從簡單返回值的方法中增加混亂。 以您的示例進一步添加上下文和含義:

public class MyClassmate {
    private Integer age;

    public MyClassmate(Integer age) {
        this.age = age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Integer getAge() {
        return age;
    }

}

這里的年齡是一個簡單的數字,似乎沒有必要在它周圍添加 getter/setter。 如果我們添加以下方法,您會很想直接訪問該字段,因為行為沒有變化:

public Integer calculateScore() {
    if(age > 21) return 100 - getNumberOfIncorrectAnswers();
    //Add 10% before for younger students
    else return (100 - getNumberOfIncorrectAnswers()) + 10;
}

然后,您的對象可能會使用依賴於您繼續直接使用它的年齡字段的方法來增加新功能。 稍后,您可能會改變年齡的產生方式並從網絡中提取價值。 您可能不想將網絡邏輯合並到構造函數中,因為這是一項昂貴的操作,只能在需要時觸發。 calculateScore()方法可以建立網絡連接並發現年齡,但所有其他依賴於年齡的方法也是如此。 但是,如果calculateScore 如下所示呢?:

public Integer calculateScore() {
    if(getAge() > 21) return 100 - getNumberOfIncorrectAnswers();
    //Add 10% before for younger students
    else return (100 - getNumberOfIncorrectAnswers()) + 10;
}

然后,您可以增強對象,改變其推導年齡的方式,而無需觸及calculateScore()方法。 這意味着您的方法遵循開放封閉原則 (OCP)。 它對增強開放但對更改關閉,或者您不必更改方法源以更改它的年齡。

根據您的應用程序和對象模型的復雜性,有時可能仍然存在封裝訪問過度的情況,但即使在這些情況下,了解直接字段訪問的權衡也是很好的,而這些更簡單的情況大多很少見。

一般來說,您應該明白封裝的需要幾乎從來都不是立竿見影的。 隨着對象的增長,它會隨着時間的推移而出現,如果對象從一開始就沒有設置封裝,那么分階段使用它的成本會更高。這就是使這種方法難以理解的原因。 需要經驗(即進行典型的過度簡化並在幾年內多次遭受痛苦)才能感覺到為什么需要封裝。 這不是你可以觀察和發現的。

也就是說,當 IDE 的功能不那么完整時,這曾經是一個比今天更大的問題。 今天,您可以在某些 IDE(如 IntelliJ)中使用內置的encapsulate fields重構來根據需要引入模式。 即使使用現代 IDE,從一開始就練習封裝仍然是有利的。

我建議使用 getter,因為在某些情況下,它可以有一些額外的邏輯(如格式化、檢查空值等)。 因此,在使用字段本身時,您可能會丟失一些邏輯。

為了保持良好的封裝性,您首先需要考慮的是您將在類之外公開哪些方法,例如,如果在這里,例如您將只使用 is allowed 方法,我將只公開該方法,並且在構造函數中定義字段,如果該字段適合更改,那么您將需要 getter/setter,但始終取決於您想從類中提供什么。 並盡可能多地封裝。

public class MyClass {
    private Integer myField;

    MyClass(Integer myField){
        this.myField = myField;
    }

    //Only this method is offered nobody need to know you use myField to say true/false
    public boolean isAllowed() {
        MyEnum.ALLOWED.equals(myField);
    }

}

在我的軟件工程課程中,我被告知要實現“秘密原則”。 因此,您應該始終使用 getter 和 setter 例程。 這樣您就可以確保沒有人意外訪問成員變量。

奇怪的函數或對象可能永遠不會看到甚至更改成員變量,除非您通過 setter 和 getter 明確告訴它們這樣做。

由於您的屬性是私有的,您只能使用 getter 或 setter 方法在其他類中安全地訪問它。 所以我會說最好的實現是遵循封裝原則的,即使用getter而不是直接訪問的實現。 這也將防止數據泄漏。

https://www.tutorialspoint.com/java/java_encapsulation.htm

暫無
暫無

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

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