2015-01-23 4 views
1

После поиска я нашел эти вопросы, но нет ответов на мой конкретный вопрос:Симуляция изменения свойств с неизменяемыми объектами

Undo/Redo with immutable objects

Why continue to use getters with immutable objects

How to write a test friendly immutable value class

Is it okay to expose the state of an immutable object

Вот setup: У меня есть im изменяемый класс следующим образом:

public class MyImmutableOb { 
    private final String name; 
    private final Collection<Integer> myNumbers; 

    public MyImmutableOb(String name) { 
     this.name = name; 
     myNumbers = new LinkedList<>(); 
    } 

    public MyImmutableOb(String name, MyImmutableOb oldOb) { 
     this.name = name; 
     myNumbers = new LinkedList<>(); 
     for (int i : oldOb.getNumbers()) myNumbers.add(i); 
    } 

    public Collection<Integer> getNumbers() { 
     return new LinkedList<>(myNumbers); 
    } 
} 

Я включил конструктор, как это, означало, чтобы имитировать изменение названия на объекте. Вопрос, действительно воспроизводит Collection в этой моды перерыв неизменности ?:

public MyImmutableOb(String name, MyImmutableOb oldOb) { 
    this.name = name; 
    myNumbers = new LinkedList<>(); 
    for (int i : oldOb.getNumbers()) myNumbers.add(i); 
} 

Я имею трудное время оборачивать вокруг моей головы этого.

+0

Член 'myNumbers' вашего« неизменяемого »класса является списком _mutable_. Ваш класс либо является, либо не является эффективным, неизменным. Ответ зависит от того, будет ли что-либо в '// и т. Д. ...' часть класса модифицировать список. –

+0

Ваш второй конструктор вызывает 'oldOb.getNumbers()', но вы не указали нам определение getNumbers(). Что оно делает? Если он просто возвращает 'oldOb.myNumbers', тогда ваш класс изменен: клиент может вызвать getNumbers(), а затем изменить список. –

+0

Это определение может помочь, да? Ха-ха, я плохо, я пошел вперед и добавил определение в. Это все методы в классе в настоящее время. – nihilon

ответ

2

Как вы обнаружили, для того, чтобы сделать экземпляры вашего класса неизменяемыми, вы должны явно указать неизменяемость в свой класс; типы объектов (в отличие от примитивных типов) являются mutable. Классы коллекций в java.util, конечно, изменяемы. Классы Java, такие как String и примитивные типы бокса Integer, Double и т. Д., Записываются как неизменные.

Ваше объявление переменной

private final String name; 

неизменен, потому что он объявлен finalи потому String объекты неизменны.

Использование ключевого слова final для переменной гарантирует, что переменной можно присвоить значение только один раз, поэтому она является отличным инструментом для разработки неизменяемого класса. Однако этого недостаточно, поскольку, если переменная назначается изменяемому объекту, тогда переменные в могут быть изменены до.

Ваше объявление переменной

private final Collection<int> myNumbers; 

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

Хорошая новость заключается в том, что класс утилиты Java Collections обеспечивает легкие обертки, чтобы сделать ваши коллекции неизменными. Это потребует изменения первого конструктора

public MyImmutableOb(String name, int... numbers) { 
    this.name = name; 
    this.myNumbers = Collections.unmodifiableList(Arrays.asList(numbers)); 
} 

так что myNumbers теперь действительно неизменен. Примечание. Я отказался от использования LinkedList, потому что нет смысла использовать эту специализированную реализацию List, когда она не может быть изменена в пределах MyImmutableOb.

Таким образом, ваш второй конструктор становится

public MyImmutableOb(String name, MyImmutableOb oldOb) { 
    this.name = name; 
    this.myNumbers = oldOb.myNumbers; 
} 

потому oldOb «s myNumbers уже неизменны, так что нет никакого смысла в копировании.

В заключение я понимаю, что вы, вероятно, захотели изменить содержимое myNumbers после строительства MyImmutableOb. Очевидно, что превращение класса в действительно неизменное означает, что ничто не может измениться в своих случаях после построения.

+1

Да, я видел, что вы избавились от «LinkedList». Для пояснения используется 'LinkedList', потому что порядок хранимых элементов имеет значение. Спасибо, почему я использовал его. Спасибо за подробное объяснение, это оценено! – nihilon