Immutable class 就是實體不能修改的 class,所有訊息都在生成實體時設定,類似的 class 有 String、BigInteger 及 BigDecimal。建立 immutable class 時,需要注意以下幾點:
- 不提供任何會修改物件狀態的方法。
- 保證該 class 不會被繼承。避免其它 class 利用繼承破壞該 class 狀態,最簡單的方式為宣告為 final class 就無法被繼承。
- 所有的 field 皆為 final。
- 所有的 field 都是 private,降低不必要的訪問性。
- 如果有可變的 (mutable) field,必須確保調用者是無法取得 field 的引用,也不要將外部傳入的引用當作 field,應使用保護性拷貝 (defensive copy)。
public final class Complex {
private final double re;
private final double im;
public Complex(double re, double im) {
this.re = re;
this.im = im;
}
public double realPart() { return re; }
public double imaginaryPart() { return im; }
public Complex plus(Complex c) {
return new Complex(re + c.re, im + c.im);
}
public Complex subtract(Complex c) {
return new Complex(re - c.re, im - c.im);
}
...
}
Immutable class 本質是 thread-safe 沒有 concurrent 問題,自然就不需要同步,理所當然可以共用。它的缺點為每一個不同的內容皆需要產生新物件,針對頻繁使用的內容,應提供 public static final 的常數,減少物件生成的數量。同時 immutable class 在作大量操作時,會產生非常多的中繼物件,它們的生命週期相當短,也沒有機會被重複使用,有可能會引起效能問題。解決方法為 class 應該提供方法,幫助相關操作或是提供 mutable class 來協助,像是 StringBuilder 與 String 即為一例子。public static final Complex ZERO = new Complex(0, 0);
public static final Complex ONE = new Complex(1, 0);
public static final Complex I = new Complex(0, 1);
Immutable class 是否一定為 final class,裡面的 field 是否一定為 final field? 可以提供 static factory method,然後使用 private constructor,同時亦可在 factory 中提供 buffer 機制,重複利用相同的物件。至於是否需定義為 final field,不一定,若是該 field 設定成本較昂貴,又不一定會用到,那就可以在方法被調用的第一次時在設定即可。private Complex(int r, int i) {
this.r = r;
this.i = i;
}
public static Complex newComplex(int r, int i) {
return new Complex(r, i);
}
如果 immutable class 實作 Serializable 介面,且 field 包含可變性的引用,就必須提供 readResolve 或是 readObject,不然會從 immutable class 中創建出 mutable 物件。即使在 mutable class 中,也應盡量限制它的可變性,這樣能降低出錯率,也更容易分析。不要在 constructor 及 public static factory 之外處,提供初始化方法。轉載請註明原文網址 https://cookieandcoketw.blogspot.com/2020/07/effective-java-17-immutable.html
沒有留言:
張貼留言