2013-08-03 31 views
6

通用設計實踐是將實例變量設置爲私有,並讓公共getter和setter來訪問它們。但很多時候,我看到互聯網上的代碼示例具有構造函數,這些構造函數直接將值賦給私有實例變量,而不是在構造函數中使用setter。我錯過了什麼嗎?Java設置構造函數中的私有字段

public class Person{ 
    private String name; 

    public Person(String name){ 
     //is this right, seems like the whole encapsulation purpose is defeated 
     this.name = name; 

     //shouldn't this be used 
     setName(name); 
    } 

    public String getName(){ 
     return this.name; 
    } 

    public void setName(String name){ 
     this.name = name; 
    } 
} 
+7

我相信使變量變爲私有的目的是將它們從**其他**類的直接操作中分離出來。 –

+2

另外,'this'關鍵字不是getter所必需的;它只在含糊不清的情況下使用(例如,如果在同一範圍內有另一個名爲「name」的變量) – ataulm

回答

5

你不會錯過任何東西。你做什麼完全取決於你的情況。但是,請考慮:

在setter中進行參數驗證非常普遍。例如,假設我有一個領域中的類,它可以通過10容納值0(以下簡稱「投」是不必要的異常以下類型,但我有它的清晰度):

public class Example { 
    private int value; 
    public Example() { 
    } 
    public final int getValue() { 
     return value; 
    } 
    public final void setValue (int value) throws IllegalArgumentException { 
     if (value < 0 || value > 10) 
      throw new IllegalArgumentException("Value is out of range."); 
    } 
} 

這裏的setValue( )驗證'價值',以確保它堅持規則。我們有一個不變量,指出「範例不會超出範圍值」。現在讓我們假設我們想要構造一個具有價值的構造函數。你可能會這樣做:

public class Example { 
    ... 
    public Example (int value) { 
     this.value = value; 
    } 
    ... 
} 

正如你所看到的,有一個問題。新示例(11)的聲明會成功,現在存在一個違反我們規則的示例。然而,如果我們使用二傳手在構造函數中,我們可以很方便的所有參數驗證添加到構造以及:

public class Example { 
    ... 
    public Example (int value) throws IllegalArgumentException { 
     setValue(value); // throws if out of range 
    } 
    ... 
} 

所以有這許多好處。

現在,仍然有些情況下您可能希望直接分配值。首先,也許你沒有setter可用(儘管我會爭辯說,創建私有或包私有setter仍然是可取的,由於上述原因,如果必要反射/ bean支持,併爲了便於在更復雜的代碼驗證)。

另一個原因可能是,您可能有一個構造函數,它知道,在某種程度上,會提前分配有效值,因此不需要驗證,並且可以直接分配變量。這通常不是跳過使用setter的有力理由。但是,總而言之,儘可能在所有地方使用setter通常是一個好主意,它通常會導致更清晰和更清晰的代碼,隨着複雜性的增加,這些代碼更容易維護。

大多數人看到人們直接設置變量的例子就是人們「懶惰」 - 如果情況允許,這是完全可以接受的(也許你正在編寫一個快速測試程序或應用程序,並且不想例如,執行一系列setter)。只要你牢記大局,在適當的時候只是「懶惰」,沒有什麼不對的。

我想根據這裏的其他答案添加一些東西:如果您在子類中重寫setter,並且您設置的數據會中斷基類所假定的不變量,那麼相關的setters應該是作出最終決定或基礎階級不應做出這些假設。 如果壓倒性的setter違反了基類不變量,那麼手頭就有更大的問題。

你會注意到getter/setter在上面的例子中是final的。這是因爲我們的規則是「任何示例必須具有從0到10的值」。因此該規則延伸至子類。如果我們沒有這個規則,並且一個例子可以採用任何值,那麼我們不需要最終的setter,並且可以允許子類覆蓋。

希望有所幫助。

+0

在最後添加了關於重寫的setter的評論。 –

0

將變量設置爲private將鼓勵來自其他類的封裝。

除非setName(String)是爲了做額外的事情(這個方法名並不意味着),當你在私有變量所在的類中時,不需要使用setter。

+1

這不是*完全* true,因爲您可以將所有驗證邏輯封裝在setter中,因此具有來自其他地方的驗證服務你的班。 –

+0

+1肯定,同意。 – ataulm

0

這並不擊敗封裝,因爲私有成員仍然從其他類

隱藏如果修改方法不包含任何邏輯,只是將成員則存在之間直接設置調用的成員沒有區別儘管爲了更好的練習,應該調用setter方法。

設置人員指示此人的姓名可能會在將來發生變化,並且可以很容易地重新創建整個人物對象。

2

有時候,當你想讓類不可變時,它只是你需要做的事情之一。在這種情況下根本就沒有setter方法。

+0

有一個爭論,主要是關於驗證,而不是私人安置者。但是,這是非常真實的,有時你只是想快速地將簡單的代碼放在一起,而且創建私人設置器很不方便,而且收益甚微。 –

0

私有變量都可以訪問在類

settng variabels私人直接隨地是從其他類

2

根據上下文封裝它們,使用getter和setter實際上是一個更大違反封裝比在構造函數中使用成員變量。如果你想設置這個類的成員變量'name',這些方法都可以工作,因爲構造對調用者是隱藏的,因此不會違反封裝。一個警告是,在構造函數中使用setName可能會在子類中調用一個可能不是您想要的子類的重寫方法(因爲它可能會在超類中留下未定義的名稱)。

下面是你類似的疑問,可以提供額外的觀點:

calling setters from a constructor

0

初始化變量內部構造是一個非常普遍的做法。它可以用來根據用戶調用的構造函數爲變量賦值。您不能基於客戶端代碼將調用setter方法將值分配給實例變量的假設來編寫代碼。在創建對象時(即在構造函數中)將默認值賦值給變量總是安全的。

根據調用代碼的要求(使用setter方法),在構造函數中初始化變量並將其設置爲不同的值之間存在差異。兩者都有不同的目的和不同的目標。

+0

我不認爲這回答了這個問題(**或者我誤解了**)。當你已經提供了setter時,OP並沒有問到在構造函數中初始化變量是否合適;相反,OP在構造函數中詢問所述setter的_use_。 – ataulm

0

這是完全正常的。一旦創建對象,可能需要初始化一些變量,因此將它們傳遞給構造函數是有意義的,並且很多時候我們可能不希望爲這些變量提供setter,以避免在創建對象後更改值。

+0

有一個論點,主要是關於驗證(特別是可能在多個地方設置的變量),而不是私人設置者。但是,這是非常真實的,有時你只是想快速地將簡單的代碼放在一起,而且創建私人設置器很不方便,而且收益甚微。 –

0

它可以直接分配值在類提供的setter不做任何其他處理。

基本上設定裝置/吸氣劑被用來提供給私人數據,如返回數據,而不是私有對象的參考的副本,在吸氣劑等驗證數據限制性訪問..

由於構造是對象的一部分本身,我們確信我們正在做的是正確的,那麼它確定。

+0

值得指出的是,這裏的關鍵聲明是「我們確信我們所做的是正確的」。如果你曾經對你的字段值施加規則,不要忘記注意確保構造函數不違反這些規則。 –

相關問題