從表面看,不變類的建立似乎是一個好方案。但是,一旦真的需要那種新類型的一個修改的對象,就必須辛苦地進行新對象的創建工作,同時還有可能涉及更頻繁的垃圾收集。對有些類來說,這個問題並不是很大。但對其他類來說(比如String類),這一方案的代價顯得太高了。
為解決這個問題,我們可以創建一個“同志”類,並使其能夠修改。以後只要涉及大量的修改工作,就可換為使用能修改的同志類。完事以後,再切換回不可變的類。
因此,上例可改成下面這個樣子:
//: Immutable2.java // A companion class for making changes // to immutable objects. class Mutable { private int data; public Mutable(int initVal) { data = initVal; } public Mutable add(int x) { data += x; return this; } public Mutable multiply(int x) { data *= x; return this; } public Immutable2 makeImmutable2() { return new Immutable2(data); } } public class Immutable2 { private int data; public Immutable2(int initVal) { data = initVal; } public int read() { return data; } public boolean nonzero() { return data != 0; } public Immutable2 add(int x) { return new Immutable2(data + x); } public Immutable2 multiply(int x) { return new Immutable2(data * x); } public Mutable makeMutable() { return new Mutable(data); } public static Immutable2 modify1(Immutable2 y){ Immutable2 val = y.add(12); val = val.multiply(3); val = val.add(11); val = val.multiply(2); return val; } // This produces the same result: public static Immutable2 modify2(Immutable2 y){ Mutable m = y.makeMutable(); m.add(12).multiply(3).add(11).multiply(2); return m.makeImmutable2(); } public static void main(String[] args) { Immutable2 i2 = new Immutable2(47); Immutable2 r1 = modify1(i2); Immutable2 r2 = modify2(i2); System.out.println("i2 = " + i2.read()); System.out.println("r1 = " + r1.read()); System.out.println("r2 = " + r2.read()); } } ///:~
和往常一樣,Immutable2包含的方法保留了對象不可變的特征,只要涉及修改,就創建新的對象。完成這些操作的是add()和multiply()方法。同志類叫作Mutable,它也含有add()和multiply()方法。但這些方法能夠修改Mutable對象,而不是新建一個。除此以外,Mutable的一個方法可用它的數據產生一個Immutable2對象,反之亦然。
兩個靜態方法modify1()和modify2()揭示出獲得同樣結果的兩種不同方法。在modify1()中,所有工作都是在Immutable2類中完成的,我們可看到在進程中創建了四個新的Immutable2對象(而且每次重新分配了val,前一個對象就成為垃圾)。
在方法modify2()中,可看到它的第一個行動是獲取Immutable2 y,然後從中生成一個Mutable(類似於前面對clone()的調用,但這一次創建了一個不同類型的對象)。隨後,用Mutable對象進行大量修改操作,同時用不著新建許多對象。最後,它切換回Immutable2。在這裡,我們只創建了兩個新對象(Mutable和Immutable2的結果),而不是四個。
這一方法特別適合在下述場合應用:
(1) 需要不可變的對象,而且
(2) 經常需要進行大量修改,或者
(3) 創建新的不變對象代價太高