“一成不变”的弊端
变类的建立似乎是一个好方案。但是,一旦真的需要那种新类型的一个修改的对象,就必须辛
苦地进行新对象的创建工作,同时还有可能涉及更频繁的垃圾收集。对有些类来说,这个问题并不是很大。
但对其他类来说(比如 String 类),这一方案的代价显得太高了。
为解决这个问题,我们可以创建一个“同志”类,并使其能够修改。以后只要涉及大量的修改工作,就可换
为使用能修改的同志类。完事以后,再切换回不可变的类。
/** * 同志类,它也含有 add() 和 multiply() 方法。但这些方法 * 能够修改 Mutable 对象,而不是新建一个。除此以外, Mutable * 的一个方法可用它的数据产生一个Immutable2 对象, * @author lsj * */ 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 Imutable2 makeImutable2(){ return new Imutable2(data) ; } } /** * 包含的方法保留了对象不可变的特征,只要涉及修改,就创建新的对象。 * @author lsj * */ public class Imutable2 { private int data ; public Imutable2(int data) { this.data = data ; } public int read (){ return data ; } public boolean nonzero (){ return data!= 0; } public Imutable2 add (int x ){ return new Imutable2(data+ x ) ; } public Imutable2 multiply(int x ){ return new Imutable2(data*x); } public Mutable makeMutable (){ return new Mutable(data) ; } /** * 在 modify1() 中,所有工作都是在 Immutable2 类中完成的, * 我们可看到在进程中创建了四个新的 Immutable2 对象(而且每次 * 重新分配了val,前一个对象就成为垃圾)。 * @param y * @return */ public static Imutable2 modify1 (Imutable2 y ){ Imutable2 val = y.add(12) ; val = val.multiply(3); val = val.add(11) ; val = val.multiply(2); return val ; } //this get the same result /** * 在方法 modify2() 中,可看到它的第一个行动是获取 Immutable2 y,然后从中生成一个 Mutable(类似于前 * 面对 clone() 的调用,但这一次创建了一个不同类型的对象)。随后,用 Mutable 对象进行大量修改操作, * 同时用不着新建许多对象。最后,它切换回 Immutable2。在这里,我们只创建了两个新对象(Mutable 和 * Immutable2 的结果),而不是四个。 * @param y * @return */ public static Imutable2 modify2 (Imutable2 y){ Mutable m = y.makeMutable() ; m.add(12).multiply(3).add(11).multiply(2) ; return m.makeImutable2() ; } public static void main (String [] args ){ Imutable2 i2 = new Imutable2(47) ; Imutable2 r1 = modify1(i2) ; Imutable2 r2 = modify2(i2 ); System.out.println(i2.read()) ; System.out.println(r1.read() ); System.out.println(r2.read() ); } }
上面 的方法适合用于:
(1) 需要不可变的对象,而且
(2) 经常需要进行大量修改,或者
(3) 创建新的不变对象代价太高