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

Инъекция зависимостей в С++

Это также вопрос, который я задал в комментарии в одном из сообщений Miško Hevery google, который касался инъекции зависимостей, но он был похоронен в комментариях.

Интересно, как может работать factory/builder шаг проводки зависимостей вместе на С++.

т.е. мы имеем класс A, который зависит от B. Строитель будет выделять B в кучу, передать указатель на B в конструкторе A, а также выделить в куче и вернуть указатель на A.

Кто после этого очищается? Хорошо ли позволить строителю очистить его после его завершения? Кажется, это правильный метод, поскольку в разговоре говорится, что строитель должен установить объекты, которые, как ожидается, будут иметь одинаковое время жизни или, по крайней мере, более длительный срок службы (у меня также есть вопрос). Что я имею в виду в коде:

class builder {
public:
    builder() :
        m_ClassA(NULL),m_ClassB(NULL) {
    }
    ~builder() {
        if (m_ClassB) {
            delete m_ClassB;
        }
        if (m_ClassA) {
            delete m_ClassA;
        }
    }
    ClassA *build() {
        m_ClassB = new class B;
        m_ClassA = new class A(m_ClassB);
        return m_ClassA;
    }
};

Теперь, если есть зависимость, которая, как ожидается, продлится дольше, чем время жизни объекта, мы вставляем ее (например, ClassC - это зависимость). Я понимаю, что мы должны изменить метод сборки на что-то вроде:

ClassA *builder::build(ClassC *classC) {
    m_ClassB = new class B;
    m_ClassA = new class A(m_ClassB, classC);
    return m_ClassA;
}

Каков ваш предпочтительный подход?

4b9b3361

Ответ 1

Этот разговор посвящен внедрению Java и зависимостей.

В С++ мы попробуем NOT передать указатели RAW. Это связано с тем, что указатель RAW не имеет связанной с ним семантики собственности. Если у вас нет собственности, мы не знаем, кто несет ответственность за очистку объекта.

Я нахожу, что большая часть инъекции зависимостей времени выполняется через ссылки в С++.
В редких случаях, когда вы должны использовать указатели, оберните их в std:: unique_ptr < > или std:: shared_ptr < > в зависимости от того, как вы хотите управлять собственностью.
Если вы не можете использовать функции С++ 11, используйте std:: auto_ptr < > или boost:: shared_ptr < > .

Я бы также отметил, что стили программирования С++ и Java теперь настолько расходятся, что применение стиля одного языка к другому неизбежно приведет к катастрофе.

Ответ 2

Это интересно, DI в С++ с использованием шаблонов:

http://adam.younglogic.com/?p=146

Я думаю, что автор делает правильные шаги, чтобы не переводить Java DI на С++ слишком буквально. Стоит прочитать.

Ответ 3

Недавно я был укушен ошибкой DI. Я думаю, что он решает множество проблем сложности, особенно автоматизированную часть. Я написал прототип, который позволяет использовать DI в симпатичном С++-способе, или, по крайней мере, я так думаю. Вы можете посмотреть здесь пример кода: http://codepad.org/GpOujZ79

То, что явно отсутствует: нет области охвата, отсутствие привязки интерфейса к реализации. Последнее довольно легко решить, первое, я понятия не имею.

Буду признателен, если у кого-то есть мнение о коде.

Ответ 4

Используйте RAII.

Передача необработанного указателя на кого-то такая же, как передача им права собственности. Если это не то, что вы хотите сделать, вы должны дать им какой-то фасад, который также знает, как очистить объект, о котором идет речь.

shared_ptr < > может это сделать; второй аргумент его конструктора может быть функциональным объектом, который знает, как удалить объект.

Ответ 5

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

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

Ответ 6

В С++, как правило, когда вы делаете все правильно, вам вообще не нужно писать деструкторы в большинстве случаев. Вы должны использовать интеллектуальные указатели для автоматического удаления объектов. Я думаю, что построитель не похож на владельца экземпляров ClassA и ClassB. Если вы не любите использовать интеллектуальные указатели, вы должны подумать об объекте жизни и их владельцах.

Ответ 7

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

Иногда кросс-зависимость неизбежна, и нет четкой собственности. Например, (m) экземпляры собственных (n) B экземпляров, а некоторые экземпляры B могут принадлежать нескольким As. В этом случае наилучшим подходом является использование подсчета ссылок для B, аналогично подсчету ссылок на COM. Любые функции, которые овладевают B *, должны сначала увеличить счетчик ссылок и уменьшить его при освобождении владения.

Я также избегаю использования boost:: shared_ptr, поскольку он создает новый тип (shared_ptr и B * становятся двумя разными типами). Я обнаружил, что при добавлении методов он приносит больше головных болей.

Ответ 8

Вы также можете проверить FFEAD Injection Dependency. Он предоставляет DI на линиях Spring для JAVA и имеет ненавязчивый способ борьбы с вещами. Он также имеет множество других важных функций, таких как встроенная поддержка AJAX, отражение, сериализация, интерпретатор С++, бизнес-компоненты для С++, ORM, Messaging, веб-сервисы, пулы потоков и сервер приложений который поддерживает все эти функции.