Есть ли цель объявить init()
метод для типа?
Я не спрашиваю, стоит ли нам отдавать предпочтение init()
конструктору или как избежать объявленияinit()
.
Я спрашиваю, есть ли какое- либо обоснование для объявления init()
метода (видя, насколько он распространен) или это запах кода, и его следует избегать.
Эта init()
идиома довольно распространена, но я пока не вижу реальной выгоды.
Я говорю о типах, которые поощряют инициализацию с помощью метода:
class Demo {
public void init() {
//...
}
}
Когда это когда-нибудь пригодится в производственном коде?
Я чувствую, что это может быть запах кода, поскольку он предполагает, что конструктор не полностью инициализирует объект, что приводит к созданию частично созданного объекта. Объект не должен существовать, если его состояние не установлено.
Это заставляет меня поверить, что это может быть частью какой-то техники, используемой для ускорения производства, в смысле корпоративных приложений. Это единственная логическая причина, по которой я могу придумать такую идиому, я просто не уверен, насколько это будет полезно в таком случае.
init()
производный класс, или наоборот?) Если это так, это пример того, как базовый класс может выполнить «пост-конструктор» "который может быть выполнен только после того, как самый производный класс закончил конструкцию. Это пример многофазной инициализации.Ответы:
Да, это запах кода. Запах кода не обязательно должен быть удален. Это то, что заставляет вас взглянуть второй раз.
Здесь у вас есть объект в двух принципиально разных состояниях: pre-init и post-init. Эти государства имеют разные обязанности, разные методы, которые могут быть вызваны, и разное поведение. Это фактически два разных класса.
Если вы физически сделаете их двумя отдельными классами, вы статически удалите целый класс потенциальных ошибок, за счет того, что ваша модель может не соответствовать "модели реального мира" так же близко. Вы обычно называют первый
Config
илиSetup
или что - то в этом роде.Поэтому в следующий раз попробуйте изменить ваши идиомы construct-init в двухклассные модели и посмотрите, как это получится для вас.
источник
this
в конструкторе является запахом кода и может привести к подверженному ошибкам коду, и избегать его рекомендуется независимо от того, к какому домену относится ваш проект).По-разному.
init
Метод является код запахом , когда нет необходимости иметь инициализации объекта , отделенные от конструктора. Иногда бывают случаи, когда имеет смысл разделить эти шаги.Быстрый поиск в Google дал мне этот пример. Я легко могу представить себе больше случаев, когда код, выполняемый во время размещения объекта (конструктор), может быть лучше отделен от самой инициализации. Возможно, у вас есть выровненная система, и распределение / построение происходит на уровне X, но инициализация только на уровне Y, потому что только Y может обеспечить необходимые параметры. Возможно, init является дорогостоящим и должен выполняться только для подмножества выделенных объектов, и определение этого подмножества может быть выполнено только на уровне Y. Или вы хотите переопределить (виртуальный) метод init в производном класс, который нельзя сделать с помощью конструктора. Возможно, уровень X предоставляет вам выделенные объекты из дерева наследования, но уровень Y не знает о конкретном выводе, только об общем интерфейсе (где
init
может быть определен).Конечно, по моему опыту, эти случаи являются лишь небольшим процентом от стандартного случая, когда вся инициализация может быть выполнена непосредственно в конструкторе, и всякий раз, когда вы видите отдельный
init
метод, может быть хорошей идеей подвергнуть сомнению его необходимость.источник
init
метода. Однако всякий раз, когда вы видите такой метод, не стесняйтесь ставить под сомнение его необходимость.init()
метода, я уверен, что мне было бы полезно узнать о его назначении. Извините за мое невежество, я просто удивлен тем, как тяжело мне время от времени находить для него применение, не позволяя мне подумать об этом, чего следует избегатьМой опыт разбивается на две группы:
В моем личном опыте я видел только несколько случаев (1), но намного больше случаев (2). Следовательно, я обычно предполагаю, что init () - это запах кода, но это не всегда так. Иногда вы просто не можете обойти это.
Я обнаружил, что использование шаблона Builder часто помогает устранить необходимость / желание иметь init ().
источник
init()
решить добавление метода?init()
Метод должен либо параметры принять зависимости, или вы должны создать экземпляр зависимостей в пределах отinit()
метода, который вы могли бы также сделать с помощью конструктора. Не могли бы вы привести пример?Типичный сценарий, когда метод Init пригодится, - это когда у вас есть файл конфигурации, который вы хотите изменить и учесть это изменение без перезапуска приложения. Это, конечно, не означает, что метод Init должен вызываться отдельно от конструктора. Вы можете вызвать метод Init из конструктора, а затем вызвать его позже, когда / если параметры конфигурации изменятся.
Подводя итог: как для большинства дилемм, является ли это запахом кода или нет, зависит от ситуации и обстоятельств.
источник
Config
?update
/reload
, вероятно, было бы более описательным для такого рода поведения), чтобы фактически зарегистрировать эти изменения. , В этом случае это уведомление приведет к внутреннему изменению значений конфига в вашем приложении, что, как я полагаю, можно наблюдать, наблюдая за вашим конфигом, уведомляя наблюдателей, когда конфиг получает указание изменить одно из его значений. Или я неправильно понимаю ваш пример?Зависит от того, как вы их используете.
Я использую этот шаблон в языках сборки мусора, таких как Java / C #, когда не хочу перераспределять объект в куче (например, когда я создаю видеоигру и мне нужно поддерживать высокую производительность, сборщики мусора снижают производительность). Я использую конструктор для других необходимых ему распределений кучи и
init
для создания базового полезного состояния прямо перед каждым повторным использованием. Это связано с концепцией объектных пулов.Это также полезно, если у вас есть несколько конструкторов, которые совместно используют общее подмножество инструкций инициализации, но в этом случае
init
они будут частными. Таким образом, я могу свести к минимуму каждый конструктор в максимально возможной степени, поэтому каждый из них содержит только свои уникальные инструкции и один вызов,init
чтобы сделать все остальное.В общем, это запах кода.
источник
reset()
метод более описательным для вашего первого утверждения? Что касается второго (много конструкторов), наличие множества конструкторов является запахом кода. Предполагается, что объект имеет несколько целей / обязанностей, что предполагает нарушение SRP. У объекта должна быть одна ответственность, и конструктор должен определить необходимые зависимости для этой одной ответственности. Если у вас есть несколько конструкторов из-за необязательных значений, они должны выдвигаться (что также является запахом кода, вместо этого следует использовать конструктор).string
список конструкторов любого языка , множество вариантов. Для меня обычно это может быть максимум 3 конструктора, но общее подмножество инструкций при инициализации имеет смысл, когда они разделяют какой-либо код, но отличаются в любом случае.String
, это можно решить, развязав создание строк. В конце концов, aString
есть aString
, и его конструктор должен принимать только то, что ему нужно, чтобы он работал как нужно. Большинство из этих конструкторов представлены для целей преобразования, что является неправильным использованием конструкторов. Конструкторы не должны выполнять логику, иначе они рискуют потерпеть неудачу при инициализации, оставляя вас с бесполезным объектом.init()
методы могут иметь некоторый смысл, когда у вас есть объекты, которым необходимы внешние ресурсы (например, сетевое соединение), которые одновременно используются другими объектами. Возможно, вы не захотите / не хотите использовать ресурс в течение всего срока службы объекта. В таких ситуациях вы можете не захотеть выделять ресурс в конструкторе, если вероятно, что распределение ресурса завершится неудачно.Особенно во встроенном программировании вы хотите иметь детерминистический след памяти, поэтому обычной (хорошей?) Практикой является ранний вызов ваших конструкторов, возможно даже статических, и инициализация только позже, когда выполняются определенные условия.
Кроме таких случаев, я думаю, что все должно идти в конструктор.
источник
init
методы слишком ограничивающие, ИМХО.Обычно я предпочитаю конструктор, который получает все аргументы, необходимые для функционального экземпляра. Это проясняет все зависимости этого объекта.
С другой стороны, я использую простую инфраструктуру конфигурации, которая требует открытого конструктора без параметров и интерфейсов для ввода зависимостей и значений конфигурации. После того, как это сделано, инфраструктура конфигурации вызывает
init
метод объекта: теперь вы получили все, что у меня есть для вас, выполните последние шаги, чтобы подготовиться к работе. Но обратите внимание: это инфраструктура конфигурации, которая автоматически вызывает метод init, так что вы не забудете его вызвать.источник
Нет никакого запаха кода, если метод init () семантически встроен в жизненный цикл состояния объекта.
Если вам нужно вызвать init (), чтобы привести объект в согласованное состояние, это запах кода.
Существует несколько технических причин, по которым такая структура существует:
источник
Имя init иногда может быть непрозрачным. Давайте возьмем машину и двигатель. Чтобы завести машину (только включить питание, прослушать радио), вы хотите убедиться, что все системы готовы к работе.
Таким образом, вы строите двигатель, дверь, колесо и т. Д. На экране отображается двигатель = выключен.
Не нужно начинать наблюдение за двигателем и т. Д., Поскольку они все дорогие. Затем, когда вы поворачиваете ключ, чтобы зажечь, вы вызываете Engine-> Start. Запускаются все дорогостоящие процессы.
Теперь вы видите двигатель = вкл. И процесс зажигания начинается.
Автомобиль не включится без наличия двигателя.
Вы можете заменить двигатель с вашим сложным расчетом. Как ячейка Excel. Не все ячейки должны быть активными со всеми обработчиками событий все время. Когда вы сосредоточены на клетке, вы можете запустить ее. Увеличение производительности таким образом.
источник