Думай на Java

       

Недостаток неизменных классов


Создание неизменных классов на первый взгляд является элегантным решением. Однако, всякий раз, когда вам понадобится модифицировать новый объект этого типа, вы должны терпеть неудобства, связанные с необходимостью создания нового объекта, а также более частым "сбором мусора". Для каких-то объектов это не составит труда, но для некоторых (таких, как класс String) сопряжено с множеством проблем.

В таком случае хорошим выходом будет создание класса-компаньона, который может изменяться. Тогда, если вам требуется произвести множество изменений, вы можете переключаться на использование редактируемого класса-компаньона, а после завершения всех модификаций вновь работать с неизменным классом.

Пример:

//: Приложение А:Immutable2.java

// Класс-компаньон для внесения изменений

// в неизменный класс.

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; } // Это приводит к тому же результату:

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 есть метод для создания Immutable2 объекта с использованием данных и наоборот. 

Два статических метода modify1() и modify2() демонстрируют два различных метода решения одной и той же задачи. В методе modify1() все действия выполняются внутри класса Immutable2 и в процессе работы создаются четыре новых Immutable2 объекта. (и каждый раз при переопределении val предыдущий объект становится мусором).

В методе modify2() первой операцией является Immutable2 y и создание Mutable объекта. (Это напоминает вызов метода clone(), рассмотренный нами ранее, но в то же время при этом создается объект нового типа). Затем объект Mutable используется для многочисленных операций не требующих создания новых объектов. В конце результаты передаются в Immutable2. Итак, вместо четырех новых объектов создаются только два (Mutable и результат Immutable2).

Такой прием имеет смысл использовать в случаях, когда:

  • Вам нужно использовать неизменные объекты и 


  • Вам необходимо их часто изменять или


  • Слишком накладно создавать новые неизменные объекты.



  • Содержание раздела