тестирование — Конфигурация высокого уровня инжектора конструктора в переполнении стека

Мои вопросы конкретно касаются внедрения зависимостей через конструктор. Я понимаю плюсы и минусы шаблона поиска сервисов, внедрения конструкторов / сеттеров и их разновидностей, однако есть кое-что, чего я не могу избежать после выбора чистого внедрения конструкторов. После прочтения многих материалов для тестируемого дизайна, в том числе тщательного изучения блога Мишко Хевери (особенно этот пост) Я в следующей ситуации:

Предположим, я пишу программу на C ++ и правильно ввел свои зависимости через их конструкторы. Для удобства чтения я предоставил объект высокого уровня, который имеет единственную функцию Execute (), вызываемую из main:

int main(int argc, char* argv[]) {
MyAwesomeProgramObject object(argc, argv);
return object.Execute();
}

Функция Execute () состоит в том, чтобы просто подключить все необходимые объекты и запустить объект самого высокого уровня. Для объекта самого высокого уровня требуется пара зависимостей, а для этих объектов требуется несколько объектов и т. Д. И т. Д., Что подразумевает функцию, которая выглядит следующим образом:

MyAwesomeProgramObject::Execute() {
DependencyOne one;
DependencyTwo two;
DependencyThree three;

MidLevelOne mid_one(one);
MidLevelTwo mid_two(two, three);

// ...

MidLevelN mid_n(mid_dependencyI, mid_dependencyJ, mid_dependencyK);

// ...

HighLevelObject1 high_one(mid_one, mid_n);
HighLevelObject2 high_two(mid_two);

ProgramObject object(high_one, high_two);
return object.Go();
}

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

В блоге упомянутый, он заявляет, что у нас должны быть фабрики на уровне жизни каждого объекта, но это, по сути, то, что делает Execute, поэтому мой код выглядит идентично его примеру:

AuditRecord audit = new AuditRecord();
Database database = new Database(audit);
Captcha captcha = new Captcha();
Authenticator authenticator =
new Authenticator(database, captcha, audit);
LoginPage = new LoginPage(audit, authenticator);

Вопросы:

  • Это правильный подход?
  • Это шаблон, который я не знаю (похоже на Maven context.xml)?
  • Для чистого инжектора конструктора, я просто несу стоимость «авансового» распределения?

4

Решение

Обратите внимание, что ваши разные примеры противоречивы. Сначала вы показываете создание объектов в стеке, а ваш последний пример размещает объекты.

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

Лично я начал использовать общие указатели, и я считаю, что это является окончательным для облегчения управления большим количеством объектов.

std::shared_ptr<foo> foo_object(new foo);
std::shared_ptr<blah> foo_object(new blah(foo));

Таким образом, blah может хранить копию общего указателя foo навсегда, и все работает, как ожидается, даже между границами функций. Мало того, что общий указатель имеет значение NULL при создании и автоматически удаляется при удалении (когда последний общий указатель удаляется, конечно.) И вы можете использовать слабый указатель в объектах, для которых указатель не всегда должен быть установлен. ..

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

0

Другие решения

Других решений пока нет …