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

Инициализировать() vs Конструктор(), правильное использование при создании объекта

Мы все знаем разницу между методом Constructor и определяемым пользователем Initialize() методом.

Мой вопрос сосредоточен на лучшей практике проектирования для создания объекта. Мы можем поместить весь код Initialize() в Constructor() и наоборот (переместите весь код разминки на Initialize метод и вызовите этот метод из Constructor).

В настоящее время, создавая новый класс, я создаю любые новые экземпляры внутри Constructor() и перемещаю любой другой код разминки в метод Initialize().

Какой лучший компромисс по вашему мнению?

4b9b3361

Ответ 1

Я думаю, что нужно учитывать несколько аспектов:

  • Конструктор должен инициализировать объект таким образом, чтобы он находился в рабочем состоянии.

  • Конструктор должен только инициализировать объект, а не выполнять тяжелую работу.

  • Конструктор не должен прямо или косвенно обращаться к виртуальным членам или внешнему коду.

Поэтому в большинстве случаев метод Initialize не требуется.

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

Ответ 2

Я недавно подумал об этом в честной битве (следовательно, нашел этот вопрос), и пока у меня нет ответа, я думал, что поделился своими мыслями.

  • Конструкторы "идеально" должны устанавливать только состояние объекта, т.е. несколько:

this.member = member;

По-моему, это хорошо играет с IoC, наследованием, тестированием и просто хорошо пахнет.

Иногда требуется тяжелая работа, поэтому я пытаюсь сделать это:

  • Перейдите в тяжелый подъем.

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

Если это невозможно и вам нужно инициализировать состояние для своего класса перед использованием, добавьте метод initialse. Это добавляет временную зависимость в ваш код, но это не обязательно плохо, особенно при использовании контейнеров IoC:

Скажите CarEngine требуется DrivingAssistComputer, а DrivingAssistComputer необходимо выполнить сильную инициализацию, то есть загрузить все параметры, проверки погодных условий и т.д. Еще одна вещь, которую следует отметить, заключается в том, что CarEngine не взаимодействует напрямую с DrivingAssistComputer, ему просто нужно, чтобы он присутствовал, делая свою собственную сторону сбоку. Фактически, двигатель может работать некорректно, если DrivingAssistComputer не выполняет свою работу в фоновом режиме (меняя какое-то состояние где-то). Если мы используем IoC, мы имеем:

// Without initialise (i.e. initialisation done in computer constructor)
public CarEngine(FuelInjectors injectors, DrivingAssistComputer computer) {
  this.injectors = injectors;
  // No need to reference computer as we dont really interact with it.
}

...

Итак, здесь мы имеем аргумент конструктора, обозначающий computer как зависимость, но фактически не использующий его. Так что это уродливо, но давайте добавим метод Initialise:

public CarEngine(FuelInjectors injectors, DrivingAssistComputer computer) {
  this.injectors = injectors;
  // This ofcourse could also be moved to CarEngine.Initialse
  computer.Initialise(); 
}

...

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

Другим вариантом является использование CarEngineFactory:

 CarEngine CreateEngine(FuelInjectors injectors) {
  new DrivingAssistComputer().Initialise(); 
  return new CarEngine(injectors);
}

...

Однако я нахожу заводы и IoC просто путают матрицу, поэтому я бы пошел на второй вариант.

Хотелось бы услышать некоторые мысли об этом.

Изменить 1: Другой вариант, который я пропустил выше, имеет метод Initialise, но перемещение этого вызова в модуль инициализации IoC. Поэтому создание и инициализация все еще несколько инкапсулированы.