不可變對象

爲什麼使用不可變對象

在大型的軟件開發過程中最大的問題是代碼的複雜性。代碼的可讀性可能是首要目標。可讀性差的代碼讓人很難對代碼的正確性快速的做出判斷。

可變對象是增加還是減少了代碼的可讀性呢?

QueryObject queryObject =newQueryObject(name, page, pageSize);

 Collection<Customter> customters = seach(queryObject); 

if(customters.isEmpty()) {

        adjustSerachCriteria(queryObject, name); 

       search(queryObject);

 } 

上面這段代碼中第二次search的時候很難判斷queryObject到底有沒有改變。需要根據第一次有沒有查詢到數據以及adjustSerachCriteria的實現才能最終判斷出來。

將上面的代碼重構成下面的方式:


QueryObject queryObject =newQueryObject(name, page, pageSize);

Collection<Customter> customters = seach(queryObject); 

if(customters.isEmpty()) {

            QueryObject newQueryObject = adjustSerachCriteria(queryObject, name); 

            search(newQueryObject); 

}

上面的代碼明確的adjustSerachCriteria方法會創建一個新的查詢對象進行search操作。


可變對象有哪些缺點

很難定位一個對象的數據有沒有被修改(一個方法調用有可能修改了入參,增加了方法的理解成本,一個方法除了返回值還對程序產生了其它影響) 閱讀代碼的層級改變了;在寫代碼時一個方法裏面的代碼層級應該是一致的,如果在調用的方法裏面修改了對象數據,在閱讀代碼,很難按照一個順序去閱讀,因爲除了閱讀方法本身之外,還需要閱讀方法調用的其它方法 如果是多線程的代碼,大大的增加了代碼問題的定位與debug難度


如何使用不可變對象

如果類型比較簡單,可以直接將類型定義成值對象(value object),下面是一個通過值對象來構建不可變對象的方法

public class Product {

private String name;

private int amount;

private long price;

public Product(String name, int amount, long price) {

     super();

    this.name = name;

    this.amount = amount;

    this.price = price;

public String  getName() {

    return   name;

public int getAmount() {

    return amount;

 } 

public long getPrice() {

     return price;

 } 

}


通過創建私有構造方法與只讀對象來實現不可變對象

當賣出一個產品時,不是在原有的product對象上面將數量減1,而是新建一個product的對象。

public  class Product {

//同上

public  Product saleOne() {

    return  new   Product(name, amount -1, price);

}

不可變對象有如下好處

可以將校驗邏輯收斂到構造函數中

對象總是處於有效的狀態

對象是線程安全的

增加了代碼的可讀性,因爲不需要跳躍到調用的方法內部去確定對象的那些成員被修改了

不可變對象的限制

由於期望改變不可變對象只有通過複製的方式來實現,所以在比較簡單跟小的類型的時候比較適用,如果一個對象很大,則複製對象會帶來性能問題,增加內存的使用與cpu消耗

另一個問題是一些對象本身就是具有可變屬性,試圖將這些對象變成不可變對象往往得不償失。

雖然存在這些限制,但是大部分情況下使用不可變對象還是十分有用的。不管使用哪種設計,都需要權限利弊,考慮得失,選擇當前場景下最適合的。

英文原文

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章