Подтвердить что ты не робот

Являются ли неизменяемые объекты хорошей практикой?

Должен ли я сделать свои классы неизменными, где это возможно?

Однажды я прочитал книгу "Эффективная Ява" Джошуа Блоха, и он рекомендовал сделать все бизнес-объекты неизменными по разным причинам. (например, безопасность потока) Это также относится к С#?

Вы пытаетесь сделать свои объекты неизменяемыми, поэтому у вас меньше проблем при работе с ними? Или это не стоит неудобства, которое вы должны создать?

4b9b3361

Ответ 1

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

Цитата из более ранней публикации, которую он ссылается на:

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

Ответ 2

Это будет скорее ответ типа мнения, но...

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

Ответ 3

Неизменяемые объекты являются центральной особенностью функционального программирования; он имеет свои преимущества и недостатки. (Например, связанные списки практически невозможно быть неизменными, но неизменные объекты делают parallelism кусок пирога.) Так как комментарий к вашему сообщению отмечен, ответ "это зависит".

Ответ 4

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

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

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

Я действительно ушел с дороги, чтобы сделать "на месте" "ToUpper", используя небезопасный код isntead встроенного String.ToUpper(). Он работает примерно в 4 раза быстрее и потребляет 1/2 пиковой памяти.

Ответ 5

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

Например, предположим, что вы используете внешнюю службу кеширования, такую ​​как memcached или Velocity или какой-либо другой, равномерно упрощенный распределенный хеш-стол. Вы можете просто использовать клиентскую библиотеку С# и назвать ее достаточно хорошим. Тем не менее, это расточительно с ресурсами, учитывая недолговечный контекст, такой как сценарий веб-запроса. Вы действительно хотите вытащить каждый объект из кеша один раз и только один раз в вашем контексте.

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

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

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