2016-12-06 82 views
2

以下哪項比較好?它甚至是基於意見的還是有任何相關的差異?在某些情況下,其中一方能受到青睞嗎?使用getter或直接訪問私人成員會更好嗎?

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

編輯: 這個帖子並沒有在鏈接的問題的答案(見註釋到戰後初期)

+0

如果你經過Java封裝和抽象,那麼我認爲第一個更可取。因爲你不直接暴露字段。 – SachinSarawgi

+0

就意義而言,沒有區別。這更多的是一個觀點問題。我會選擇**實現1 **,因爲您一定會獲得想要測試的值,例如,如果您有,例如,任何類型的轉碼編碼 – DamCx

+2

您應該對此進行詳細閱讀:http:// stackoverflow .com/questions/1568091/why-use-getters-and-setters – rafid059

回答

5

下列哪些比較好?它甚至是基於意見的還是與 有任何相關的區別?可以在 某些情況下受到青睞嗎?

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

作爲一般規則,如果不需要,您應該避免間接。 MyClass的當前實例具有其中一個字段中的信息來執行操作。它不需要隱藏自己的內部狀態。
因此在內部,MyClass沒有任何理由贊成使用getMyField()而不是直接使用myField字段。
getMyField()訪問者更適合該班的客戶使用。
所以我認爲,這是在任何情況下,你的示例代碼更好:

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

編輯
除了可讀性,這裏有一個例子,爲什麼你有沒有興趣耦合的內部狀態的公共getter。
假設在開發階段您從課程中刪除public getMyField()方法,因爲不需要或不再需要該課程的客戶,如果isAllowed()在其實施中依賴於getMyField(),它將被破壞,您應該將其替換爲myField

+0

這個答案有點誤導性,因爲這個例子過於簡單並且沒有語義意義。 getMyField名稱沒有表達任何意圖或含義。該方法被命名爲「getSecurityLevel」,它會更好地表達其意圖。實際上你永遠不會刪除這個方法,因爲它會改變程序的語義。相反,你會改變getter的實現來改變isAllowed的行爲。這裏考慮的主要是OCP。 – Cliff

+0

@Cliff爲什麼你想讓問題更復雜?問題是:我應該使用同一個類的方法中的公共getter還是private字段?我沒有具體說明,但我的例子中,我提到刪除getter方法是指在開發階段進行刪除。有時候,您會自動爲許多領域(IDE幫助)提供getter,因爲您需要或者您認爲在產生它們時需要它,並且在開發結束時查看該類時,您會注意到不應該提供吸氣劑。無論如何, – davidxxx

+0

。這個例子可能確實是誤導性的。所以,我更新它來指定上下文。 – davidxxx

-1

在我的軟件工程課程中,我被告知要實現「祕密原則」。因此,你應該總是使用getter和setter例程。通過這種方式,您可以確保沒有人偶然訪問成員變量。

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

+1

人們可以使用getter和setter來「意外」訪問變量。那麼你有什麼意見? – rafid059

+0

不小心訪問'myField'而不是'getMyField()'更容易。 – Kapa11

1

我會建議使用getter,因爲在某些情況下,它可以有一些額外的邏輯(如格式化,檢查空值等)。所以你在使用該領域時可能會失去一些邏輯。

+1

是不是添加邏輯的getter-setter方法被認爲是一種不好的做法? –

+1

吸氣劑應該沒有邏輯。 – Chris311

+1

@AlexErohin和Chris311--當然邏輯在getter中是允許的。否則,「隱藏執行變更」的全部內容將會丟失。假設一個字段現在是'int'。您決定將實現更改爲枚舉。吸氣劑的合同保持不變,因爲它已被其他類發佈和使用。因此,不是在其中有'return x;',而是類似於'return x.getIntValue()' - 這是getter中的邏輯,並且非常好。 – RealSkeptic

-1

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

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

+1

我的字段被封裝。這篇文章沒有提到訪問同一類中的變量。 – Chris311

0

要保持一個良好的封裝,第一個想你需要思考的是你要你的類外,如果在這裏公開哪些方法,例如,你打算只使用被允許的方法,我將只作公開該方法,並定義構造函數中的字段,如果該字段是合適的改變,那麼你需要的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); 
    } 

} 
+0

讓我們假設getter和setter從班級外面被調用。 – Chris311

+0

然後我會添加getters/setters並保持相同的字段訪問 – cralfaro

+0

好吧,這與接受的答案然後。 – Chris311

3

我的答案不會是最豐富的,但它會來自處理這種模式的直接經驗。在設計一個對象時,通常很容易直接訪問成員字段,而不是依賴訪問器。這種慾望源於想要簡化對象並避免在簡單返回值的方法中添加混亂。以你的例子更進了一步添加上下文&含義:

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更大的問題。今天,您可以使用內置的encapsulate fields重構IntelliJ這樣的IDE來根據需要引入模式。即使使用現代IDE,從一開始實踐封裝仍然是有利的。

+0

有趣的反例。對於這個例子來說,年齡可能是一個太簡單的屬性,但同樣是一個很好的例子 – davidxxx

+0

是的,我正在打字的時候編寫了這個例子。不是最好的解釋,而是粗略的方法來向原始代碼引入意義和上下文,否則它就像一系列機械步驟而不是講故事一樣開始閱讀。 – Cliff

+0

@Cliff:在你的例子中,你正在利用getter。如果將要從網絡中檢索年齡,則應該利用匯編程序或工廠來創建「MyClassmate」。我不認爲邏輯應該直接進入「MyClassmate」。否則它不再是getter,而是一個'computeAge()' - 方法。 – Chris311