2012-09-07 180 views
21

如果我有一個重載構造函數的客戶類(默認和一個帶參數)什麼是在重載構造函數中設置類成員的正確方法是什麼?使用「this」引用或使用setter方法?類最佳實踐

只是不確定適當的方法是什麼。

public class Customer { 

private String firstName; 
private String lastName; 
private int age; 

public Customer() {} 

//This Way 
public Customer(String firstName, String lastName, int age) 
{ 
    this.firstName = firstName; 
    this.lastName = lastName; 
    this.age = age; 
} 

// Or this way? 
    public Customer(String firstName, String lastName, int age) 
{ 
    setFirstName(firstName); 
    setLastName(lastName); 
    setAge(age); 
} 



/** 
* @return the firstName 
*/ 
public String getFirstName() { 
    return firstName; 
} 

/** 
* @param firstName the firstName to set 
*/ 
public void setFirstName(String firstName) { 
    this.firstName = firstName; 
} 

/** 
* @return the lastName 
*/ 
public String getLastName() { 
    return lastName; 
} 

/** 
* @param lastName the lastName to set 
*/ 
public void setLastName(String lastName) { 
    this.lastName = lastName; 
} 

/** 
* @return the age 
*/ 
public int getAge() { 
    return age; 
} 

/** 
* @param age the age to set 
*/ 
public void setAge(int age) { 
    this.age = age; 
} 

}

回答

27

第一個(使用this.)可能更安全,更直接。考慮未來的子類是否會覆蓋setter方法 - 這可能會導致非常意外的行爲。

如果你的課是最終的,這是無關緊要的,它是一個洗滌。

+4

更好地傳達意圖,那麼您可以更自由地處理這種情況。這是目前爲止唯一明智的答案。事實上,由於這個問題,幾個皮棉工具會警告從構造函數調用非最終方法。 (如果班級不是最終的,但是設置方法是這樣的,那就好。) –

+0

@KumarVivekMitra - 我不喜歡你的回答,因爲我對它的評論表明。 –

+0

@TedHopp請再次閱讀我的答案......我認爲我們兩人都在說同一件事情.....還是讓我再一次把它寫在這裏......我認爲你正在採取'OCP'原則,,,類是可以擴展的,但是對於修改是封閉的。正如我所知道的那樣,構造函數不能被繼承,所以不能被覆蓋,所以它的不可變性......' –

0

基本上,有除了驗證沒有差別。一方面,如果您的設置器僅基於新值驗證新值(它們不依賴於對象狀態),則調用setter可避免重複驗證邏輯。另一方面,如果一個setter的驗證檢查其他屬性,那麼您必須確保在調用setter之前已經設置了所需的屬性,或者直接指定屬性。

0

直接訪問的方式更快(如果內存正確地爲我提供服務,速度會提高7倍),但如果某些特殊規則指定這些值或分配鏈接(第二個是「安全」另一個設置者),在訪問器中實現的情況下,當然除非你想在構造函數完成賦值時明確地繞過這些規則/鏈接。

總之,這取決於您的需求,但這些是我能想到的主要問題。

+0

除非setter方法(或類)是'final',否則第二種方法遠不是「更安全」。如果一個子類覆蓋了setter並且未能調用超類呢? –

+1

如果你繼承一個類型並且重載setter方法而不用設置任何東西,那麼你就會遇到一個比決定使用哪個構造器更大的問題。 –

+0

@TedHopp我寫了一篇很長的關於約旦·懷特所說的話的描述,所以我會把它留在:) – JTMon

1

最好的答案是「依賴」。一般情況下,除非設置者在設置值之前做更多的計算,否則不需要使用setter。但是,如果您的設置人員僅直接設置值,那麼this可能最適合您。相反,setter用於驗證和東西,如果你使用this,你會錯過它們。

2

由於不知道這是一種更好的方式來做到這一點,但你想出來的東西......

-如果你希望你的類是mutable,然後用setters去。

-如果你想讓你的課程成爲Immutable,那麼我認爲使用this是一個更好的選擇。

我認爲使用this,適用於從Web服務器或某個源接收一些數據的地方,然後將它們以自定義類的實例的形式存儲到集合中.....

如:

  • 創建一個類學生,

  • 當你做一些網絡服務的請求,你會得到響應,爲如:JSON ..

  • 解析它,然後創建學生實例並將其存儲在集合中。

    如:

    ArrayList<Student> arList = new ArrayList<Student>();

    arList.add(new Student(name,rollNos,class,marks));

+0

從構造函數調用非final方法(如setter)不是一個好主意。參見例如[本文](http://www.informit.com/articles/article.aspx?p=20521)。 –

+0

@TedHopp我認爲你正在採取'OCP'原則,,,類是擴展開放,但關閉修改....並且我知道'構造函數不能被繼承,所以不能被覆蓋,所以它的不可變。 ...' –

+0

請參閱[this](https://www.securecoding.cert.org/confluence/display/java/MET05-J.+Ensure+that+constructors+do+not+call+overridable+methods)for一個很好的解釋,爲什麼一個人不應該從構造函數調用一個可重寫的方法。大多數lint工具會抱怨從構造函數調用setter方法(除非方法或類是final的,或者方法是私有的 - 在這種情況下,方法不能被覆蓋)。 –

0

正如已經指出這是相當危險的調用構造函數重寫的方法。但是,如果您需要在setter中執行某種驗證,您仍然有一些明智的方法來實現它。

  1. 使制定者最終。最快的解決方案。這個已經被陳述了,但它不是唯一的選擇。
  2. 使用二傳手的私人副本
  3. 使用工廠方法而不是構造函數。我通常堅持這一個。因爲這樣,如果驗證失敗並且它比(2)