Стратегия инициализации ООП - PullRequest
0 голосов
/ 02 января 2012

Мне часто приходится выбирать между этими двумя стратегиями для проектирования объекта:

  1. Объект, который полностью инициализирован и готов к использованию после его создания.Конструктор часто требует сложного списка параметров, поэтому инициализация объекта нетривиальна.Все объекты, имеющие ее в качестве переменной-члена, также будут нуждаться в нетривиальных конструкторах.Это может привести к коду, сложность которого сосредоточена на конструкторах объектов, что часто усложняет код.
  2. Объект с конструктором по умолчанию.Переменные объекта устанавливаются индивидуально с помощью setter methods.Недостатком этого подхода является то, что большинству методов необходимо проверять, полностью ли инициализирован объект, что усложняет код.

Каково ваше личное предпочтение между ними и как вы решаете, когда его использовать?или другой?

Ответы [ 4 ]

2 голосов
/ 02 января 2012

Ни.Огромные списки параметров указывают, что объект делает слишком много.Множество свойств, которые необходимо установить, прежде чем объект сможет получить действительный и полезный вывод, указывает, что он делает слишком много.Так что ни один из подходов, на мой взгляд, не является решением.

Есть много способов разбить эти вещи, но вне конкретного сценария единственное правило - «Это нужно сделать».

Агрегирование в другие объекты, классы «контроллера», различные шаблоны коммуникаторов.Являются ли некоторые категории объектами первого класса, некоторые могут быть скрыты в реализации.

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

2 голосов
/ 02 января 2012

Если конструктор принимает много аргументов & mdash; Вы называете эту нетривиальную инициализацию объекта & mdash; и вы не хотите разбивать ваш класс на более мелкие, тогда одна альтернатива - поместить параметры в объект параметров , а затем только передать этот объект конструктору.

Во-вторых, я считаю, что вы должны различать ...

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

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

Существует также альтернатива первому типу свойств (те, которые должны обязательно иметь значение, предоставленное пользователем): свойства, которые предоставляются путем переопределения абстрактного метода получения в производном классе:

abstract class ComplicatedFoo {
    protected abstract T getSomeDependency(); // replaces required ctor parameter
}

P.S .: Книга Дханджи Р. Прасанны (Manning Publications) «Введение зависимостей» дает хороший обзор различных способов инициализации объекта.

2 голосов
/ 02 января 2012

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

0 голосов
/ 02 января 2012

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

Не стоит делать конструктор таким сложным, потому что вы не можете вернуть ошибку в конструкторе (я не знаю, нормально ли создавать исключение в конструкторе или нет, потому что я в особенностине люблю исключения где угодно).Кроме того, вы не можете вызывать там виртуальные функции и т. Д.

Мне нравится подход, когда сложное конструирование класса заключается в создании функции init.Тогда я могу сделать что-то вроде:

Person::Person()
{
    age = -1;
    ...
}

int Person::Init()
{
    age = functionThatReturnsTheAgeFromSomeDB();
    if (age == -1 )
    {
        return DB_ERROR;
    }
    ...
}

И так далее.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...