Мне нравится неизменный «шаблон» из-за его сильных сторон, и в прошлом я находил его полезным для разработки систем с неизменными типами данных (некоторые, большинство или даже все). Часто, когда я это делаю, я пишу меньше ошибок, и отладка становится намного проще.
Однако мои сверстники в целом уклоняются от неизменности. Они не совсем неопытны (отнюдь не так), но все же пишут объекты данных классическим способом - частные члены с геттером и сеттером для каждого члена. Тогда обычно их конструкторы не принимают аргументов или, возможно, просто принимают некоторые аргументы для удобства. Так часто создание объекта выглядит так:
Foo a = new Foo();
a.setProperty1("asdf");
a.setProperty2("bcde");
Может быть, они делают это везде. Может быть, они даже не определяют конструктор, который принимает эти две строки, независимо от того, насколько они важны. И, возможно, они не изменяют значение этих строк позже и никогда не должны. Ясно, что если бы все это было правдой, объект был бы лучше спроектирован как неизменный, верно? (конструктор принимает два свойства, вообще не устанавливает).
Как вы решаете, должен ли тип объекта быть неизменным? Есть хороший набор критериев, чтобы судить об этом?
В настоящее время я спорю о том, стоит ли переключать несколько типов данных в моем собственном проекте на неизменяемые, но мне пришлось бы обосновать это для своих коллег, и данные в типах могут (ОЧЕНЬ редко) меняться - в это время вы, конечно, можете изменить это неизменный способ (создайте новый, скопировав свойства из старого объекта, за исключением тех, которые вы хотите изменить). Но я не уверен, является ли это просто моей любовью к неизменным, или есть ли в них реальная потребность / польза от них.
источник
Ответы:
Похоже, вы приближаетесь к нему задом наперед. По умолчанию следует неизменным. Делайте объект изменчивым только в том случае, если вы абсолютно не можете / не можете заставить его работать как неизменный объект.
источник
Основным преимуществом неизменяемых объектов является гарантия безопасности резьбы. В мире, где использование множества ядер и потоков является нормой, это преимущество стало очень важным.
Но использовать изменяемые объекты очень удобно. Они хорошо работают, и если вы не изменяете их из отдельных потоков, и у вас есть хорошее понимание того, что вы делаете, они достаточно надежны.
источник
Есть два основных способа решить, является ли объект неизменным.
а) в зависимости от характера объекта
Легко уловить эти ситуации, потому что мы знаем, что эти объекты не изменятся после его создания. Например, если у вас есть
RequestHistory
сущность, и по своей природе сущности истории не изменяются после ее создания. Эти объекты могут быть спроектированы как неизменяемые классы. Имейте в виду, что объект запроса является взаимозаменяемым, так как он может изменять свое состояние, кому он назначен и т. Д. С течением времени, но история запросов не изменяется. Например, был элемент истории, созданный на прошлой неделе, когда он перешел из отправленного в назначенное состояние, и это право истории никогда не может измениться. Так что это классический неизменный случай.б) Исходя из выбора дизайна, внешние факторы
Это похоже на пример java.lang.String. Строки на самом деле могут меняться с течением времени, но по своей конструкции они сделали его неизменным из-за факторов кэширования / пула строк / факторов параллелизма. Аналогично, кэширование / параллелизм и т. Д. Могут сыграть хорошую роль в том, чтобы сделать объект неизменным, если в приложении жизненно важны кэширование / параллелизм и связанная с ним производительность. Но это решение должно быть принято очень осторожно после анализа всех воздействий.
Основным преимуществом неизменяемых объектов является то, что они не подвергаются шаблону с переворачиванием. Т.е. объект не претерпит никаких изменений в течение срока службы, и это делает кодирование и обслуживание очень очень легкими.
источник
Минимизация состояния программы очень выгодна.
Спросите их, хотят ли они использовать изменяемый тип значения в одном из ваших классов для временного хранения из клиентского класса.
Если они говорят да, спросите почему? Изменяемое состояние не относится к подобному сценарию. Заставить их создать состояние, к которому они действительно принадлежат, и сделать состояние ваших типов данных как можно более явным, - это отличные причины.
источник
Ответ несколько зависит от языка. Ваш код выглядит как Java, где эта проблема настолько сложна, насколько это возможно. В Java объекты могут быть переданы только по ссылке, а клон полностью поврежден.
Простого ответа не существует, но наверняка вы хотите сделать объекты с малыми значениями неизменяемыми. Java правильно сделала Strings неизменяемыми, но неправильно сделала Date и Calendar изменяемыми.
Поэтому определенно сделайте объекты небольших значений неизменяемыми и реализуйте конструктор копирования. Забудьте все о Cloneable, он настолько плохо спроектирован, что бесполезен.
Для объектов с большими значениями, если неудобно делать их неизменяемыми, сделайте их легкими для копирования.
источник
В некоторой степени нелогично, никогда не нужно менять строки позже, это довольно хороший аргумент, что не имеет значения, являются ли объекты неизменяемыми или нет. Программист уже рассматривает их как эффективно неизменные, независимо от того, применяет ли это компилятор или нет.
Неизменность обычно не вредит, но не всегда помогает. Простой способ определить, может ли ваш объект извлечь выгоду из неизменности, состоит в том, если вам когда-либо понадобится сделать копию объекта или получить мьютекс перед его изменением . Если оно никогда не изменится, то неизменность на самом деле ничего не покупает, а иногда усложняет.
Вы делаете есть хороший пункт о риске построения объекта в нерабочем состоянии, но это действительно отдельный вопрос от неизменности. Объект может быть как изменяемым, так и всегда в действительном состоянии после создания.
Исключением из этого правила является то, что, поскольку Java не поддерживает ни именованные параметры, ни параметры по умолчанию, иногда бывает неудобно создавать класс, который гарантирует действительный объект только с использованием перегруженных конструкторов. Не так много в случае с двумя свойствами, но есть кое-что, что можно сказать и о согласованности, если этот шаблон часто встречается с аналогичными, но более крупными классами в других частях вашего кода.
источник
Object
функциям", тогда непосредственное изменение объекта не было бы семантически ничем не отличается от перезаписи ссылки ссылкой на новый объект, который был идентичны, но для указанного изменения. IMHO, одна из самых больших семантических слабостей в Java заключается в том, что у нее нет средств, с помощью которых код может указывать, что переменная должна быть единственной неэфемерной ссылкой на что-то; ссылки должны передаваться только методам, которые не могут сохранить копию после их возврата.У меня может быть слишком низкоуровневое представление об этом, и, вероятно, потому что я использую C и C ++, которые не совсем упрощают создание всего неизменного, но я вижу неизменяемые типы данных как детали оптимизации , чтобы написать больше эффективные функции, лишенные побочных эффектов, и способные очень легко предоставлять такие функции, как отмена систем и неразрушающее редактирование.
Например, это может быть очень дорого:
... если
Mesh
он не предназначен для использования в качестве постоянной структуры данных и вместо этого был типом данных, который требовал полного его копирования (который в некоторых случаях может охватывать гигабайты), даже если все, что мы собираемся сделать, это изменить часть этого (как в вышеупомянутом сценарии, где мы изменяем только позиции вершин).Вот тогда-то я и достиг неизменности и спроектировал структуру данных, чтобы позволить копировать немодифицированные части и подсчитывать ссылки, чтобы позволить вышеупомянутой функции быть достаточно эффективной без необходимости глубокого копирования целых мешей при сохранении возможности записи функция без побочных эффектов, которая значительно упрощает безопасность потоков, исключений, возможность отмены операции, ее неразрушающего применения и т. д.
В моем случае слишком дорого (по крайней мере, с точки зрения производительности) сделать все неизменным, поэтому я оставляю его для классов, которые слишком дороги для полного копирования. Эти классы, как правило, представляют собой здоровенные структуры данных, такие как сетки и изображения, и я обычно использую изменяемый интерфейс для выражения изменений в них через объект «строитель», чтобы получить новую неизменяемую копию. И я делаю это не столько для того, чтобы попытаться достичь неизменных гарантий на центральном уровне класса, сколько для того, чтобы помочь мне использовать класс в функциях, которые могут быть свободны от побочных эффектов. Мое желание сделать
Mesh
неизменяемым выше не состоит в том, чтобы сделать сетки неизменяемыми напрямую, а позволить легко писать функции, свободные от побочных эффектов, которые вводят меш и выводят новый, не платя при этом огромной памяти и вычислительных затрат.В результате у меня всего 4 неизменных типа данных во всей моей кодовой базе, и все они - здоровенные структуры данных, но я интенсивно использую их, чтобы помочь мне написать функции, которые не имеют побочных эффектов. Этот ответ может быть применим, если, как и я, вы работаете на языке, который не позволяет сделать все неизменным. В этом случае вы можете сместить фокус на то, чтобы основная часть ваших функций избегала побочных эффектов, и в этот момент вы можете захотеть сделать отдельные структуры данных неизменяемыми, типы PDS, в качестве детали оптимизации, чтобы избежать дорогостоящих полных копий. Между тем, когда у меня есть такая функция:
... тогда у меня нет соблазна сделать векторы неизменяемыми, поскольку они достаточно дешевы, чтобы просто копировать полностью. Здесь нет никакого выигрыша в производительности, превращая Векторы в неизменные структуры, которые могут копировать неизмененные части. Такие затраты перевесят стоимость простого копирования всего вектора.
источник
Если Foo имеет только два свойства, тогда легко написать конструктор, который принимает два аргумента. Но предположим, что вы добавили еще одно свойство. Затем вы должны добавить еще один конструктор:
На данный момент, это все еще управляемо. Но что, если есть 10 свойств? Вам не нужен конструктор с 10 аргументами. Вы можете использовать шаблон построителя для создания экземпляров, но это добавляет сложности. К этому времени вы будете думать, «почему я просто не добавил сеттеры для всех свойств, как это делают обычные люди»?
источник