Неизменность после внедрения зависимости, инициализации

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

Есть ли языки, которые удовлетворяют мой интерес - которые формализуют DI, инициализацию, и поддерживают неизменность этим способом? Возможно, это является немым для создания их частью языка; возможно, нет. Я не уверен.

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

Мысли?

6
задан Ladlestein 25 May 2010 в 20:19
поделиться

5 ответов

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

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

3
ответ дан 16 December 2019 в 21:35
поделиться

Существует два основных способа создания неизменяемых объектов:

  1. использование паттерна builder/factory - builder может быть изменяемым, но создаваемые им объекты неизменяемы, обычно реализуются с помощью конечных полей. Вы также можете объединить эти два подхода, тогда сам объект используется для создания новых экземпляров, обычно с помощью методов "mutator", которые изменяют состояние отдельного, нового экземпляра. Примером этого является FactoryBean от Spring.

  2. создайте подкласс MutableObject, который поддерживает флаг для изменяемого состояния. Все ваши мутаторы проверяют состояние mutable перед внесением изменений - если объект был установлен в состояние immutable, то проверка вызывает исключение, в противном случае изменение продолжается.

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

Использование второго подхода особенно полезно при работе с spring. Вы можете указать spring вызвать метод после инициализации боба, например seal(), который запечатывает объект - делает его неизменяемым. В качестве альтернативы вы можете реализовать небольшой BeanFactoryPostProcessor, чтобы делать это автоматически, не забывая устанавливать init-method="seal". для каждого неизменяемого боба.

4
ответ дан 16 December 2019 в 21:35
поделиться

В Java, если вы все равно используете методы мутатора для выполнения своих настроек, довольно дешево (хотя и довольно уродливо в моих глазах) добавить логику для предотвращения изменений, когда объект инициализируется.

public void setMyProperty(String newValue) {
   checkInitialized();
   myProperty = newValue;
}

public void checkInitialized() {
   if ( initialized ) {
      throw new IllegalStateException("Setter called after initialization");
   }
}

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

0
ответ дан 16 December 2019 в 21:35
поделиться

В Java вы можете использовать построитель для инициализации неизменяемого объекта в его конструкторе, поэтому вам следует избегать сеттеров.

Если вы используете Scala, неизменяемость будет по умолчанию .

1
ответ дан 16 December 2019 в 21:35
поделиться

Чтобы указать, что класс неизменяем, вы можете использовать аннотацию @Immutable.

Вы можете посмотреть Javadoc здесь.

Это хорошо работает с плагином Findbugs в Eclipse.

@Alexander:

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

Фрагмент из Javadoc:

Из необходимости это означает, что все публичные поля являются конечными, и что все публичные конечные поля ссылаются на другие неизменяемые объекты

0
ответ дан 16 December 2019 в 21:35
поделиться
Другие вопросы по тегам:

Похожие вопросы: