Injection de dépendance en C++

C'est aussi une question que j'ai posée dans un commentaire dans L'un des Google talks de Miško Hevery qui traitait de l'injection de dépendance mais qui a été enterré dans les commentaires.

Je me demande comment l'étape usine / constructeur de câblage des dépendances ensemble peut fonctionner en C++.

C'est-à-dire que nous avons une classe A qui dépend de B. Le constructeur allouera B dans le tas, passera un pointeur à B dans le constructeur de A tout en allouant dans le tas et retournera un pointeur vers A.

Qui nettoie après? Est-il bon de laisser le constructeur nettoyer après que c'est fait? Cela semble être la méthode correcte car dans le discours, il est dit que le constructeur devrait configurer des objets qui devraient avoir la même durée de vie ou au moins les dépendances ont une durée de vie plus longue (j'ai aussi une question à ce sujet). Ce que je veux dire dans le code:

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;
    }
};

Maintenant, s'il y a une dépendance qui devrait durer plus longtemps que la durée de vie de l'objet, nous l'injectons dans (disons ClassC est-ce dépendance) je comprends que nous devrions changer la méthode de construction à quelque chose comme:

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

Quelle est votre approche préférée?

23
demandé sur Yorgos Pagles 2008-12-09 17:26:17

8 réponses

Cette présentation concerne Java et l'injection de dépendances.

En C++, nous essayons Pas de passer des pointeurs bruts. C'est parce qu'un pointeur brut n'a pas de sémantique de propriété associée. Si vous n'avez pas de propriété, puis nous ne savons pas qui est responsable du nettoyage de l'objet.

Je trouve que la plupart du temps l'injection de dépendance se fait via des références en C++.
Dans les rares cas où vous devez utiliser des pointeurs, enveloppez-les dans std:: unique_ptr ou std::shared_ptr, selon la façon dont vous souhaitez gérer la propriété.
Si vous ne pouvez pas utiliser les fonctionnalités c++11, utilisez std::auto_ptr ou boost::shared_ptr.

Je voudrais également souligner que les styles de programmation C++ et Java sont maintenant si divergents que l'application du style d'un langage à l'autre conduira inévitablement à un désastre.

13
répondu Martin York 2016-03-03 13:53:10

C'est intéressant, DI En C++ en utilisant des modèles:

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

Je pense que l'auteur fait les bons gestes pour ne pas traduire Java DI en C++ trop littéralement. La peine de la lire.

9
répondu Igor Zevaka 2009-12-23 01:08:02

J'ai récemment été mordu par le bug DI. Je pense que cela résout beaucoup de problèmes de complexité, en particulier la partie automatisée. J'ai écrit un prototype qui vous permet d'utiliser DI d'une manière assez C++, ou du moins je le pense. Vous pouvez jeter un oeil à l'exemple de code ici: http://codepad.org/GpOujZ79

Les choses qui manquent évidemment: pas de portée, pas de liaison de l'interface à l'implémentation. Ce dernier est assez facile à résoudre, le premier, je n'en ai aucune idée.

Je serais reconnaissant si quelqu'un ici a une opinion sur le code.

6
répondu cheez 2010-05-10 16:39:21

Utilisez RAII.

Remettre un pointeur brut à quelqu'un revient à lui donner la propriété. Si ce n'est pas ce que vous voulez faire, vous devez leur donner une sorte de façade qui sait aussi comment nettoyer de l'objet en question.

Shared_ptr peut le faire; le deuxième argument de son constructeur peut être un objet de fonction qui sait comment supprimer l'objet.

3
répondu Kaz Dragon 2008-12-09 16:40:16

En C++, normalement, lorsque vous avez bien fait les choses, vous n'avez pas besoin d'écrire des destructeurs dans la plupart des cas. Vous devez utiliser des pointeurs intelligents pour supprimer les choses automatiquement. Je pense que builder ne ressemble pas au propriétaire des instances ClassA et ClassB. Si vous n'aimez pas utiliser des pointeurs intelligents, vous devriez penser à la durée de vie des objets et à leurs propriétaires.

2
répondu Lazin 2008-12-09 15:14:02

Les choses se compliquent si vous ne vous réglez pas une fois pour toutes sur la question de la propriété. Vous devrez simplement décider dans votre implémentation s'il est possible que les dépendances vivent plus longtemps que les objets dans lesquels elles sont injectées.

Personnellement, je dirais non: l'objet dans lequel la dépendance est injectée va nettoyer après. Essayer de le faire via le constructeur signifie que le constructeur devra vivre plus longtemps que la dépendance et l'objet dans lequel il se trouve injecter. Cela provoque plus de problèmes qu'il n'en résout, à mon avis, parce que le constructeur ne sert plus de but utile après la construction avec l'injection de dépendance a été terminée.

2
répondu Joris Timmermans 2009-11-09 12:13:13

Sur la base de ma propre expérience, il est préférable d'avoir des règles de propriété claires. Pour les petits objets concrets, il est préférable d'utiliser la copie directe pour éviter la dépendance croisée.

Parfois, la dépendance croisée est inévitable, et il n'y a pas de propriété claire. Par exemple, (M) les instances A possèdent (n) Les instances B, et certaines instances B peuvent être détenues par plusieurs As. Dans ce cas, la meilleure approche consiste à appliquer le comptage de référence à B, de la même manière que le comptage de référence COM. Toutes les fonctions qui prennent la possession de B* doit d'abord augmenter le nombre de références et le diminuer lors de la libération de la possession.

J'évite également d'utiliser boost:: shared_ptr car il crée un nouveau type (shared_ptr et B * deviennent deux types distincts). J'ai trouvé que cela apporte plus de maux de tête quand j'ajoute des méthodes.

2
répondu cuteCAT 2009-12-23 16:04:06

Vous pouvez également vérifier le injection de dépendance FFEAD. Il fournit DI sur les lignes de Spring pour JAVA et a une façon non envahissante de traiter les choses. Il a également beaucoup d'autres fonctionnalités importantes comme le Support AJAX intégré,la réflexion,la sérialisation,L'interpréteur C++, Les composants métier pour C++,ORM,la messagerie,les services Web,les Pools de threads et un serveur d'applications qui prend en charge toutes ces fonctionnalités.

1
répondu Sumeet 2011-05-28 07:04:54