Change Reference to Value (將引用對象改成值對象)

Summary:

你有一個引用對象,很小且不可變,並且不易管理。將它變成一個值對象。 java

Motivation:

若是引用對象開始變得難以使用,也許就應該將它改成值對象。引用對象必須被某種方式控制,你老是必須向其控制者請求適當的引用對象。它們可能形成內存區域之間錯綜複雜的關聯。在分佈系統和併發系統中,不可變的值對象特別有用,由於你無需考慮它們的同步問題。 併發

值對象有一個很是重要的特性:它們應該是不可變的。不管什麼時候,只要你調用同一個對象的同一個查詢函數,都應該獲得一樣的結果。若是保證了這一點,就能夠放心地以多個對象表示同一個事物。若是值對象是可變的,就必須確保對某一對象的修改會自動更新其餘「表明相同事物」的對象。這臺痛苦了,與其如此還不如把它變成引用對象。 函數

這裏有必要澄清一下「不可變」的意思。若是以Money類表示「錢」的概念,其中有「幣種」和「金額」兩條信息,那麼Money對象一般是一個不可變對象。這並不是意味着薪資不能變,而是意味着:若是要改變薪資,就須要使用另外一個Money對象來取代現有的Money對象,而不是在現有的Money對象上修改。你和Money對象之間的關係能夠改變,可是Money對象自身不能改變。 測試

Mechanics:

1.檢查重構目標是否爲不可變對象,或是否可修改成不可變對象。 this

若是該對象目前還不是不可變的,就使用Remove Setting Method,直到它成爲不可變爲止。 spa

若是沒法將該對象修改成不可變的,就放棄使用本項重構。 code

2.創建equals() 和hashCode(). 對象

3.編譯,測試。 內存

4.考慮是否能夠刪除工廠函數,並將構造函數聲明爲public。 get

範例

        咱們從一個表示「貨幣種類」的Currency類開始:

public class Currency
{
    private String code;

    public String getCode()
    {
        return code;
    }

    private Currency( String code )
    {
        this.code = code;
    }
}

這個類所作的就是保存並返回一個貨幣種類代碼。它是一個引用對象,因此若是要獲得它的實例,必須這麼作:

Currency usd = Currency.get("USD");
Currency類維護一個包含全部Currency實例的鏈表。咱們不能直接使用構造函數建立實例,由於Currency構造函數是private的。

要把一個引用對象變成值對象,關鍵動做是:檢查它是否可變。若是不是,就不能使用本項重構,由於可變的值對象會形成煩人的別名問題。

在這裏,Currency對象是不可變的,因此下一步就是爲它定義equals();

public boolean equals( Object arg )
 {
     if( !( arg instanceof Currency ) )
     {
          return false;
     }
     Currency other = ( Currency ) arg;
     return ( code.equals( other.getCode() ) );
}

定義了equals(),就必須同時定義hashcode()。實現hashcode() 有個簡單辦法:讀取equals()使用的全部字段的hash碼,而後對它們進行按位異或(^)操做。本例中,這很容易實現,由於equals()只是用了一個字段:

public int hashCode()
{
    return code.hashCode();
}
完成這兩個函數後,咱們能夠編譯並測試。這兩個函數的修改必須同時進行,不然依賴hash的任何集合對象(例如Hashtable、HashSet和HashMap)均可能產生意外行爲。

如今,咱們能夠建立任意多個Currency對象,還能夠把構造函數聲明爲public,直接以構造函數獲取Currency實例,從而去掉Currency類中的工廠函數和控制實例建立行爲。

相關文章
相關標籤/搜索