Initialize () против метода Constructor (), правильное использование при создании объекта - PullRequest
28 голосов
/ 11 декабря 2010

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

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

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

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

Ответы [ 2 ]

25 голосов
/ 11 декабря 2010

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

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

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

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

Таким образом, в большинстве случаев метод Initialize не требуется.

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

3 голосов
/ 11 июня 2011

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

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

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.Таким образом, создание и инициализация все еще несколько заключены в капсулу.

...