1. 程式人生 > 實用技巧 >不可變物件

不可變物件

可變性最小化

1. 不可變類的概念

不可變類是指其例項不能被修改的類——例項包含的資訊必須在建立例項的時候就提供,並且在物件的整個生命週期(lifetime)內固定不變。在 Java 類庫中就有許多這樣的不可變類,例如 String、BigDecimal、BigInteger、基本型別的包裝類。設計者將類設計成不可變類的理由有很多:易於設計、已於使用、更加安全、不易出錯。

1.1 優點

因為不可變物件可以只有一種狀態(即物件被建立時的狀態),所以如果需要使類的物件滿足某種約束條件,僅需在建構函式新增約束即可,只要物件能被成功建立,之後使用物件時就不再需要進行校驗。

不可變物件本質上是執行緒安全的

,它們不要求同步。當多個執行緒併發訪問不可變物件時,它們不會遭到破壞。這無疑是獲得執行緒安全最容易的方式。因此,不可變物件可以自由的被共享

1.2 缺點

不可變物件唯一的缺點是:對於每個不同的值都需要一個單獨的物件,而某些物件建立的代價可能很大。

2. 不可變類的設計原則

設計不可變類,需要遵循以下規則:

  1. 不提供任何可以修改物件狀態的方法

  2. 確保類不會被拓展。這樣做的目的是防止子類破壞該類的不可變性,常用的做法是將類宣告為 final 的。

  3. 宣告所有的域都是 final 的

  4. 宣告所有的域都是 private 的。這樣做的目的是防止客戶端訪問並修改域所指向的可變物件。

  5. 確保對於任何可變元件的互斥訪問

    。如果類具有指向可變物件的域,必須確保該類的客戶端無法獲得指向這個物件的引用。並且,永遠不要直接使用客戶端提供的物件引用初始化這樣的域,在必要的時候進行保護性拷貝(defensive copy)。

    graph LR class_[類] customer[客戶端] changeableObject(可變物件) class_ --> changeableObject customer --> changeableObject

    保護性拷貝:

    graph LR class_[類] customer[客戶端] changeableObject(可變物件) cloneObject(拷貝物件) class_ --> cloneObject customer --> changeableObject

3. 函式式方法

基於給定的運算元進行運算但不會修改運算元的方法被稱為函式式方法(functional method),與之相反,運算元在運算的過程中會被改變的方法被稱為過程式方法(procedural method)、命令式方法(imperative method)。

/**
 * @author xzy
 * @date 2020-09-08 20:32
 * 說明:二維座標點
 */
public class Point {
    /** x軸座標 */
    private final double x;
    /** y軸座標 */
    private final double y;

    public double getX() { return x; }

    public double getY() { return y; }

    public Point(double x, double y) { this.x = x; this.y = y; }

    /**
     * 向左移動
     *
     * @param x - 左移距離
     * @return - 新座標點
     */
    public Point onTheLeft(double x) {
        return new Point(this.x - x, this.y);
    }
}

上面程式碼中的 onTheLeft 方法就是一個函式式方法。一般函式式方法都以介詞命名,過程式方法都以動詞命名,以強調運算元的狀態是否改變。