Зачем нам нужен неизменный класс? - PullRequest
70 голосов
/ 22 сентября 2010

Я не могу понять, по каким сценариям нам нужен неизменный класс.
Сталкивались ли вы когда-либо с такими требованиями?или не могли бы вы дать нам какой-нибудь реальный пример, где мы должны использовать этот шаблон.

Ответы [ 19 ]

1 голос
/ 20 июня 2018

Неизменяемые объекты - это экземпляры, состояние которых не изменяется после их инициирования. Использование таких объектов зависит от конкретного требования.

Неизменяемый класс хорош для целей кэширования и безопасен для потоков.

1 голос
/ 22 сентября 2010

Использование последнего ключевого слова не обязательно делает что-то неизменным:

public class Scratchpad {
    public static void main(String[] args) throws Exception {
        SomeData sd = new SomeData("foo");
        System.out.println(sd.data); //prints "foo"
        voodoo(sd, "data", "bar");
        System.out.println(sd.data); //prints "bar"
    }

    private static void voodoo(Object obj, String fieldName, Object value) throws Exception {
        Field f = SomeData.class.getDeclaredField("data");
        f.setAccessible(true);
        Field modifiers = Field.class.getDeclaredField("modifiers");
        modifiers.setAccessible(true);
        modifiers.setInt(f, f.getModifiers() & ~Modifier.FINAL);
        f.set(obj, "bar");
    }
}

class SomeData {
    final String data;
    SomeData(String data) {
        this.data = data;
    }
}

Просто пример, демонстрирующий, что ключевое слово "final" используется для предотвращения ошибок программиста, и не намного. Принимая во внимание, что переназначение значения без конечного ключевого слова может произойти случайно, переход к этой длине для изменения значения должен быть сделан преднамеренно. Это там для документации и предотвращения ошибок программиста.

1 голос
/ 02 мая 2012

Одна особенность неизменяемых классов, которая еще не была вызвана: хранение ссылки на глубоко неизменяемый объект класса является эффективным средством хранения всего содержащегося в нем состояния.Предположим, у меня есть изменяемый объект, который использует глубоко неизменяемый объект для хранения информации о состоянии на 50 КБ.Предположим, далее, что я хочу 25 раз сделать «копию» моего оригинального (изменяемого) объекта (например, для буфера «отменить»);состояние может меняться между операциями копирования, но обычно это не так.Создание «копии» изменяемого объекта просто потребует копирования ссылки на его неизменное состояние, поэтому 20 копий просто составят 20 ссылок.Напротив, если бы состояние содержалось в изменяемых объектах на 50 тыс., Каждая из 25 операций копирования должна была бы создавать свою собственную копию данных на 50 тыс.;хранение всех 25 копий потребует хранения в основном дублированных данных.Даже если первая операция копирования создаст копию данных, которая никогда не изменится, а другие 24 операции теоретически могут просто сослаться на это, в большинстве реализаций не будет никакого способа для второго объекта, запрашивающего копиюинформация, позволяющая узнать, что неизменная копия уже существует (*).

(*). Иногда можно использовать один паттерн: изменяемые объекты имеют два поля для хранения своего состояния - одно в изменяемой форме и однонеизменная форма.Объекты могут быть скопированы как изменяемые или неизменные, и они могут начать жизнь с того или иного набора ссылок.Как только объект хочет изменить свое состояние, он копирует неизменяемую ссылку на изменяемую (если это еще не было сделано) и делает недействительной неизменную ссылку.Когда объект копируется как неизменяемый, если его неизменяемая ссылка не установлена, будет создана неизменяемая копия, и неизменная ссылка указывает на это.Этот подход потребует несколько больше операций копирования, чем «полноценная копия при записи» (например, запрос копирования объекта, который был мутирован, поскольку последняя копия потребует операции копирования, даже если исходный объект никогда не мутирует снова), но это позволяет избежать сложностей с потоками, которые может повлечь за собой FFCOW.

1 голос
/ 22 сентября 2010

Они также дают нам гарантию.Гарантия неизменности означает, что мы можем расширить их и создать новые шаблоны для эффективности, которые иначе невозможны.

http://en.wikipedia.org/wiki/Singleton_pattern

1 голос
/ 22 сентября 2010

Одной из причин "потребности" в неизменяемых классах является сочетание передачи всего по ссылке и отсутствия поддержки представлений объекта только для чтения (например, C ++ const).

Рассмотрим простой случай, когда класс поддерживает шаблон наблюдателя:

class Person {
    public string getName() { ... }
    public void registerForNameChange(NameChangedObserver o) { ... }
}

Если бы string не было неизменным, класс Person не смог бы правильно реализовать registerForNameChange(), потому что кто-то мог написать следующее, эффективно изменив имя человека, не вызывая никакого уведомления.

void foo(Person p) {
    p.getName().prepend("Mr. ");
}

В C ++ getName(), возвращающий const std::string&, имеет эффект возврата по ссылке и предотвращения доступа к мутаторам, что означает, что неизменяемые классы не нужны в этом контексте.

1 голос
/ 22 сентября 2010

Неизменяемые структуры данных также могут помочь при кодировании рекурсивных алгоритмов. Например, предположим, что вы пытаетесь решить проблему 3SAT . Одним из способов является следующее:

  • Выберите неназначенную переменную.
  • Дайте ему значение ИСТИНА. Упростите экземпляр, убрав предложения, которые теперь удовлетворены, и вернитесь к решению более простого экземпляра.
  • Если рекурсия в случае ИСТИНА не удалась, вместо этого присвойте эту переменную ЛОЖЬ. Упростите этот новый экземпляр и повторите его, чтобы решить.

Если у вас есть изменяемая структура для представления проблемы, то при упрощении экземпляра в ветви ИСТИНА вам придется либо:

  • Следите за всеми изменениями, которые вы делаете, и отмените их все, как только вы поймете, что проблема не может быть решена. Это приводит к большим накладным расходам, потому что ваша рекурсия может быть довольно глубокой, и ее сложно написать.
  • Сделайте копию экземпляра, а затем измените копию. Это будет медленно, потому что если ваша рекурсия имеет глубину в несколько десятков уровней, вам придется делать много копий экземпляра.

Однако, если вы кодируете это умным способом, вы можете иметь неизменную структуру, где любая операция возвращает обновленную (но все еще неизменную) версию проблемы (аналогично String.replace - она ​​не заменяет строку, просто дает вам новый). Наивный способ реализовать это состоит в том, чтобы иметь «неизменяемую» структуру, просто скопировав и создав новую в любой модификации, уменьшив ее до 2-го решения при наличии изменяемой, со всеми этими накладными расходами, но вы можете сделать это более эффективный способ.

0 голосов
/ 04 января 2018

Почему неизменный класс?

Как только объект создан, его состояние не может быть изменено при жизни. Что также делает его безопасным для потоков.

Примеры:

Очевидно, String, Integer, BigDecimal и т. Д. Как только эти значения созданы, их нельзя изменить при жизни.

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

0 голосов
/ 08 мая 2017

Благодаря неизменяемости вы можете быть уверены, что поведение / состояние базового неизменяемого объекта не изменится, благодаря чему вы получаете дополнительное преимущество при выполнении дополнительных операций:

  • Вы можете легко использовать несколько ядер / обработку ( параллельная / параллельная обработка ) (поскольку последовательность операций больше не будет иметь значения.)

  • Может выполнять кэширование для дорогостоящих операций (как вы уверены в том же результате
    ).

  • Может с легкостью выполнить отладку (поскольку история выполнения больше не будет проблемой
    )

0 голосов
/ 27 июля 2015

из эффективной Java;Неизменяемый класс - это просто класс, экземпляры которого нельзя изменить.Вся информация, содержащаяся в каждом экземпляре, предоставляется при его создании и фиксируется на весь срок службы объекта.Библиотеки платформы Java содержат много неизменяемых классов, включая String, классы в штучной упаковке и BigInteger и BigDecimal.Для этого есть много веских причин: неизменяемые классы легче проектировать, реализовывать и использовать, чем изменяемые классы.Они менее подвержены ошибкам и более безопасны.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...