2013-05-20 76 views
2

我想爲我的代碼庫創建一些不可變對象。真正傳達一個給定的類是不可變的消息的最好方法是什麼?我應該讓所有的字段都是最終的,並在對象構建過程中進行初始化? (這看起來很尷尬......)我應該創建一些不可變的接口,並讓對象實現它嗎? (由於Java在這背後沒有一些標準接口,所以我認爲他們有一些其他方式來處理它。)處理這個問題的標準方式是什麼? (如果它只是加入了一堆圍繞着田野的感嘆,他們不應該被修改初始化一次意見做,那也沒關係。)在Java中創建不可變對象

+1

你究竟關心什麼?是否你的同事不理解並且會修改你的課程使其變得可變? –

+0

是的,確切地說。恐怕未來看到代碼的人不會完全理解這樣一個事實,即課堂背後的設計是不可改變的,而且他們可能會爲將來等設計人員。 – Sal

回答

7

我應該對象的構造過程中讓所有我的領域決賽,並初始化?

是的。並確保這些類型本身是不可變的,或者當您從getter方法返回值時創建副本。並讓課堂本身最終成爲現實。 (否則你對自己的類可能是不可改變的,但是,這並不意味着你的類的任何實例是不可變的 - 因爲它可能是一個可變的子類的實例)

(這似乎好不尷尬...)

很難知道該怎麼不知道你如何覺得這是尷尬的建議 - 但建造者模式往往是有用的。我通常使用嵌套的靜態類,通常使用靜態工廠方法。所以你最終得到:

Foo foo = Foo.newBuilder() 
    .setName("asd") 
    .setPoints(10) 
    .setOtherThings("whatever") 
    .build(); 
+2

+1爲'並確保這些類型本身是不可變的。你怎麼說不可變的接口或註解是類似於Serializable接口的元數據? – Craig

+1

@Craig你在考慮[this](http://jsr-305.googlecode.com/svn/trunk/javadoc/javax/annotation/concurrent/Immutable.html)。 –

+0

謝謝喬恩,這回答了我的問題。爲了回答你的問題,我簡單地發現,讓每個領域都非常尷尬,因爲我通常不會在迄今爲止看到的代碼中看到它。 – Sal

5

是的,沒有。讓所有的領域都是最終的並不是一個保證。如果您想深入瞭解此問題,Joshua Bloch在Effective Java中有許多章節處理不變性和涉及的考慮因素。 Effective Java中的第15項涵蓋了其中的大部分內容,並引用了其他正在討論的項目。

他提供了這五個步驟:

  1. 不提供修改對象的狀態(稱爲muta- 職權範圍)的任何方法。

  2. 確保類不能擴展。

  3. 使所有領域決賽。

  4. 使所有領域的私人。

  5. 確保任何可變組件獨佔訪問。

一個學習如何做到這一切的辦法就是看語言設計者如何讓班級不變通過審查類,如字符串,它是不可變的(例如見http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java)源。

+1

第5點要點是什麼意思? –

+1

以下是Joshua Bloch在Effective Java中關於第5項的寫法:'如果您的類有任何引用可變對象的 字段,請確保類的客戶端無法獲得對這些對象的引用 。永遠不要將這樣的字段初始化爲客戶提供的對象 引用或從訪問者返回對象引用 – andreih

+1

這也稱爲製作*防禦副本*。 –

1

寫單元測試,如果你的同事使課堂可變將會失敗。

使用Mutability Detector,你可以寫這樣一個測試:

import static org.mutabilitydetector.unittesting.MutabilityAssert.assertImmutable; 

@Test public void isImmutable() { 
    assertImmutable(MyImmutableThing.class) 
} 

如果同事走來,並且,例如,添加一個setter方法類,測試將失敗。您的使用案例是Mutability Detector的核心目的之一。

聲明:我寫了。