Summary:類中的某個字段應該在對象建立時被設值,而後就再也不改變。去掉該字段的全部設值函數。java
動機: 程序員
若是你爲某個字段提供了設值函數,這就暗示這個字段值能夠被改變。若是你不但願在對象建立以後此字段還有機會被改變,那就不要爲它提供設值函數(同時將該字段設爲final)。這樣你的意圖會更加清晰,而且能夠排除其值被修改的可能性—這種可能性每每是很是大的。函數
若是你保留了間接訪問變量的方法,就可能常常有程序員盲目使用它們。這些人甚至會在構造函數中使用設值函數!他們或許是爲了代碼的一致性,但卻忽視了設值函數日後可能帶來的混淆。測試
作法:spa
1. 檢查設值函數被使用的狀況,看它是否只被構造函數調用,或者被構造函數所調用的另外一個函數調用。rest
2.修改構造函數,使其直接訪問設值函數所針對的那個變量。code
à若是某個子類經過設值函數給超類的某個private字段設了值,那麼你就不能這樣修改。這種狀況下你應該試着在超類中提供一個protected函數(最好是構造函數)來給這些字段設值。不論你怎麼作,都不要給超類中的函數起一個與設值函數混淆的名字。對象
3. 編譯,測試。rem
4.移除這個設值函數,將它所針對的字段設爲finalget
5.編譯,測試。
範例:
下面是一個簡單的例子:
class Account{ private String _id; Account(String id){ setId(id); } void setId(String arg){ _id = arg; } }
以上代碼可修改成:
class Account{ private String _id; Account(String id){ _id = id; } }
問題可能以幾種不一樣的形式出現。首先,你可能會在設值函數中對傳入的參數作運算:
class Account{ private String _id; Account(String id){ setId(id); } void setId(String arg){ _id = "zz" + arg; } }
若是對參數的運算很簡單(就像上面這樣)並且又只有一個構造函數,咱們能夠直接在構造函數中作相同的修改。若是修改很複雜,或者有一個以上的函數調用它,就須要提供一個獨立函數。咱們須要爲新函數起個好名字,清楚表達改函數的用途:
class Account{ private String _id; Account(String id){ initializeId(id); } void initializeId(String arg){ _id = "zz" + arg; } }
若是須要對超類的private變量賦初值,狀況就比較麻煩一些:
class InterestAccount extends Account ... private double _interestRate; InterestAccount(String id, double rate){ setId(id); _interestRate = rate; }
問題是咱們沒法在InterestAccount中直接訪問id變量。最好的解決辦法就是使用超類構造函數:
class InterestAccount ... InterestAccount(String id, doulbe rate){ super(id); _interestRate = rate; }
若是不能那樣作,那麼使用給一個命名良好的函數就是最好的選擇:
class InterestAccount ... InterestAccount(String id, doulbe rate){ initializeId(id); _interestRate = rate; }
另一種須要考慮的狀況就是對一個集合設值:
class Person{ Vector getCourses(){ return _courses; } void setCourses(Vector arg){ _courses = arg } private Vector _courses; }
在這裏,咱們應該將設值函數替換爲add操做和remove操做,Encapsulate Collection中談到了這一點