Другие перечислили множество возможных причин (и правильные объяснения того, почему большинство из них, как правило, не очень хорошая идея).Позвольте мне опубликовать один пример (более или менее) правильного использования методов init, что на самом деле связано с синхронизацией .
. В предыдущем проекте у нас было много классов Service иобъекты, каждый из которых был частью иерархии, и перекрестные ссылки друг на друга различными способами.Поэтому, как правило, для создания ServiceA вам необходим родительский объект службы, который, в свою очередь, нуждается в контейнере службы, который уже зависит от наличия некоторых конкретных служб (возможно, включая сам ServiceA) во время инициализации.Причина заключалась в том, что во время инициализации большинство служб регистрировалось другими службами в качестве прослушивателей определенных событий и / или уведомляло другие службы о событии успешной инициализации.Если другой службы не существовало на момент уведомления, регистрация не происходила, поэтому эта служба не получала важные сообщения позже, во время использования приложения.Чтобы разорвать цепочку циклических зависимостей , нам пришлось использовать явные методы инициализации отдельно от конструкторов, таким образом эффективно делая глобальную инициализацию службы двухфазным процессом .
Таким образом, хотя этой идиоме не следует придерживаться в целом, ИМХО она имеет несколько действительных применений.Однако лучше всего ограничить его использование до минимума, используя конструкторы всякий раз, когда это возможно.В нашем случае это был устаревший проект, и мы еще не до конца понимали его архитектуру.По крайней мере, использование методов init было ограничено классами обслуживания - обычные классы были инициализированы через конструкторы.Я полагаю, что мог бы быть способ реорганизовать эту архитектуру, чтобы устранить необходимость в методах инициализации службы, но, по крайней мере, я не видел, как это сделать (и, честно говоря, в то время, когда я был, у нас были более срочные проблемычасть проекта).