Quels sont les avantages des conteneurs d'injection de dépendance?


104

Je comprends les avantages de l'injection de dépendance elle-même. Prenons le printemps par exemple. Je comprends également les avantages d'autres fonctionnalités de Spring comme AOP, des aides de différents types, etc. Je me demande simplement quels sont les avantages de la configuration XML tels que:

<bean id="Mary" class="foo.bar.Female">
  <property name="age" value="23"/>
</bean>
<bean id="John" class="foo.bar.Male">
  <property name="girlfriend" ref="Mary"/>
</bean>

par rapport à l'ancien code java tel que:

Female mary = new Female();
mary.setAge(23);
Male john = new Male();
john.setGirlfriend(mary);

qui est plus facile à déboguer, à vérifier le temps de compilation et peut être compris par quiconque ne connaît que java. Alors, quel est le but principal d'un framework d'injection de dépendances? (ou un morceau de code qui montre ses avantages.)


MISE À JOUR:
En cas de

IService myService;// ...
public void doSomething() {  
  myService.fetchData();
}

Comment le framework IoC peut-il deviner quelle implémentation de myService je veux être injectée s'il y en a plus d'une? S'il n'y a qu'une seule implémentation d'une interface donnée et que je laisse le conteneur IoC décider automatiquement de l'utiliser, il sera cassé après l'apparition d'une deuxième implémentation. Et s'il n'y a intentionnellement qu'une seule implémentation possible d'une interface, vous n'avez pas besoin de l'injecter.

Ce serait vraiment intéressant de voir un petit morceau de configuration pour IoC qui montre ses avantages. J'utilise Spring depuis un moment et je ne peux pas fournir un tel exemple. Et je peux montrer des lignes simples qui démontrent les avantages de la mise en veille prolongée, du dwr et d'autres frameworks que j'utilise.


MISE À JOUR 2:
Je me rends compte que la configuration IoC peut être modifiée sans recompilation. Est-ce vraiment une si bonne idée? Je peux comprendre quand quelqu'un veut changer les informations d'identification de la base de données sans recompiler - il n'est peut-être pas développeur. Dans votre pratique, à quelle fréquence quelqu'un d'autre que le développeur modifie la configuration IoC? Je pense que pour les développeurs, il n'y a aucun effort pour recompiler cette classe particulière au lieu de changer la configuration. Et pour les non-développeurs, vous voudrez probablement lui rendre la vie plus facile et fournir un fichier de configuration plus simple.


MISE À JOUR 3:

Configuration externe du mappage entre les interfaces et leurs implémentations concrètes

Qu'est-ce qui est si bon pour le rendre extenal? Vous ne rendez pas tout votre code externe, alors que vous le pouvez certainement - placez-le simplement dans le fichier ClassName.java.txt, lisez et compilez manuellement à la volée - wow, vous avez évité de recompiler. Pourquoi éviter la compilation?!

Vous gagnez du temps de codage car vous fournissez des mappages de manière déclarative, pas dans un code procédural

Je comprends qu'une approche parfois déclarative fait gagner du temps. Par exemple, je déclare une seule fois un mappage entre une propriété de bean et une colonne de base de données et hibernate utilise ce mappage lors du chargement, de l'enregistrement, de la construction de SQL basé sur HSQL, etc. C'est là que fonctionne l'approche déclarative. Dans le cas de Spring (dans mon exemple), la déclaration avait plus de lignes et avait la même expressivité que le code correspondant. S'il y a un exemple où une telle déclaration est plus courte que le code - je voudrais le voir.

Le principe d'inversion du contrôle permet des tests unitaires faciles car vous pouvez remplacer les implémentations réelles par de fausses (comme le remplacement d'une base de données SQL par une base de données en mémoire)

Je comprends l'inversion des avantages du contrôle (je préfère appeler le modèle de conception discuté ici comme injection de dépendance, car l'IoC est plus général - il existe de nombreux types de contrôle et nous n'en inversons qu'un seul - le contrôle de l'initialisation). Je demandais pourquoi quelqu'un a jamais besoin d'autre chose qu'un langage de programmation pour cela. Je peux certainement remplacer de vraies implémentations par de fausses en utilisant du code. Et ce code exprimera la même chose que la configuration - il initialisera simplement les champs avec de fausses valeurs.

mary = new FakeFemale();

Je comprends les avantages de la DI. Je ne comprends pas quels avantages sont ajoutés par la configuration XML externe par rapport à la configuration de code qui fait de même. Je ne pense pas que la compilation devrait être évitée - je compile tous les jours et je suis toujours en vie. Je pense que la configuration de DI est un mauvais exemple d'approche déclarative. La déclaration peut être utile si elle est déclarée une fois ET est utilisée plusieurs fois de différentes manières - comme hibernate cfg, où le mappage entre la propriété du bean et la colonne DB est utilisé pour enregistrer, charger, créer des requêtes de recherche, etc. La configuration Spring DI peut être facilement traduite en configurer le code, comme au début de cette question, n'est-ce pas? Et il n'est utilisé que pour l'initialisation du bean, n'est-ce pas? Ce qui veut dire qu'une approche déclarative n'ajoute rien ici, n'est-ce pas?

Lorsque je déclare le mappage d'hibernation, je donne simplement quelques informations à l'hibernation, et cela fonctionne en fonction de cela - je ne lui dis pas quoi faire. En cas de printemps, ma déclaration dit exactement au printemps ce qu'il faut faire - alors pourquoi le déclarer, pourquoi ne pas le faire?


DERNIÈRE MISE À JOUR: Les
gars, beaucoup de réponses me parlent de l'injection de dépendance, ce que JE SAIS EST BON. La question concerne le but de la configuration DI au lieu de l'initialisation du code - j'ai tendance à penser que l'initialisation du code est plus courte et plus claire. La seule réponse que j'ai eue jusqu'ici à ma question, c'est qu'elle évite la recompilation, lorsque la configuration change. Je suppose que je devrais poster une autre question, car c'est un grand secret pour moi, pourquoi la compilation devrait être évitée dans ce cas.


21
Enfin quelqu'un a eu le courage de poser cette question. Pourquoi voudriez-vous en effet éviter la recompilation lorsque votre implémentation change au prix de sacrifier (ou au moins de dégrader) le support outil / IDE?
Christian Klauser

3
Il semble que le titre ne soit pas tout à fait correct. L'auteur a dit que les conteneurs IOC sont bien, mais semble avoir un problème avec l'utilisation de la configuration XML au lieu de la configuration via le code (et assez juste aussi). Je suggérerais peut-être "Quels sont les avantages de la configuration des conteneurs IOC via XML ou d'autres approches sans code?"
Orion Edwards

Les exemples @Orion que j'ai fournis (avec Homme et Femme) ne nécessitent aucun conteneur IOC. Je suis d'accord avec IOC; utiliser le conteneur, qu'il soit configuré en utilisant XML ou non, est toujours une question ouverte pour moi.
Pavel Feldman

@Orion 2: Bien que j'utilise une forme ou une autre d'IOC dans la plupart des projets, certains d'entre eux bénéficient du conteneur IOC autant qu'ils bénéficient du conteneur d'assignation de variable ou du conteneur de déclaration If - le langage suffit souvent pour moi. Je n'ai aucun problème à recompiler les projets sur lesquels je travaille et à séparer le code d'initialisation dev / test / production. Donc pour moi, le titre est bien.
Pavel Feldman

Je vois des problèmes avec l'échantillon. Un des principes est des services d'injection, pas de données
Jacek Cz

Réponses:


40

Pour moi, l'une des principales raisons d'utiliser un IoC (et d'utiliser une configuration externe) concerne les deux domaines suivants:

  • Essai
  • Maintenance de production

Essai

Si vous divisez vos tests en 3 scénarios (ce qui est assez normal dans le développement à grande échelle):

  1. Test unitaire
  2. Test d'intégration
  3. Test de la boîte noire

Ce que vous voudrez faire, c'est pour les deux derniers scénarios de test (intégration et boîte noire), ne recompiler aucune partie de l'application.

Si l'un de vos scénarios de test vous oblige à modifier la configuration (par exemple: utiliser un autre composant pour imiter une intégration bancaire, ou effectuer une charge de performance), cela peut être facilement géré (cela présente les avantages de la configuration du côté DI d'un IoC cependant.

De plus, si votre application est utilisée sur plusieurs sites (avec une configuration de serveur et de composant différente) ou a une configuration changeante sur l'environnement en direct, vous pouvez utiliser les étapes ultérieures de test pour vérifier que l'application gérera ces modifications.

Production

En tant que développeur, vous n'avez pas (et ne devriez pas) avoir le contrôle de l'environnement de production (en particulier lorsque votre application est distribuée à plusieurs clients ou à des sites distincts), c'est pour moi le réel avantage d'utiliser à la fois une configuration IoC et externe. , car il appartient à l'infrastructure / support de production de peaufiner et d'ajuster l'environnement en direct sans avoir à retourner chez les développeurs et à travers des tests (coût plus élevé quand tout ce qu'ils veulent faire est de déplacer un composant).

Résumé

Les principaux avantages de la configuration externe d'un IoC proviennent du fait de donner à d'autres (non-développeurs) le pouvoir de configurer votre application, d'après mon expérience, cela n'est utile que dans un ensemble limité de circonstances:

  • L'application est distribuée sur plusieurs sites / clients où les environnements seront différents.
  • Contrôle de développement limité / entrée sur l'environnement de production et la configuration.
  • Scénarios de test.

En pratique, j'ai constaté que même lorsque vous développez quelque chose sur lequel vous avez le contrôle sur l'environnement sur lequel il sera exécuté, il est préférable au fil du temps de donner à quelqu'un d'autre les capacités de modifier la configuration:

  • Lors du développement, vous ne savez pas quand cela changera (l'application est si utile que votre entreprise la vend à quelqu'un d'autre).
  • Je ne veux pas être obligé de changer le code à chaque fois qu'un léger changement est demandé qui aurait pu être géré en configurant et en utilisant un bon modèle de configuration.

Remarque: Application fait référence à la solution complète (pas seulement à l'exécutable), donc à tous les fichiers nécessaires à l'exécution de l'application .


14

L'injection de dépendance est un style de codage qui trouve ses racines dans l'observation que la délégation d'objet est généralement un modèle de conception plus utile que l'héritage d'objet (c'est-à-dire que l'objet a une relation est plus utile que l'objet est une relation). Un autre ingrédient est cependant nécessaire pour que DI fonctionne, celui de créer des interfaces objets. En combinant ces deux modèles de conception puissants, les ingénieurs en logiciel ont rapidement réalisé qu'ils pouvaient créer un code flexible faiblement couplé et ainsi est né le concept d'injection de dépendance. Cependant, ce n'est que lorsque la réflexion d'objet est devenue disponible dans certains langages de haut niveau que la DI a vraiment pris son envol. La composante réflexion est au cœur de la plupart des jours d'aujourd'hui '

Un langage doit fournir une bonne prise en charge des techniques de programmation orientées objet normales ainsi que la prise en charge des interfaces d'objets et de la réflexion d'objets (par exemple Java et C #). Bien que vous puissiez créer des programmes en utilisant des modèles DI dans les systèmes C ++, son manque de prise en charge de la réflexion dans le langage proprement dit l'empêche de prendre en charge les serveurs d'applications et d'autres plates-formes DI et limite par conséquent l'expressivité des modèles DI.

Points forts d'un système construit à partir de modèles DI:

  1. Le code DI est beaucoup plus facile à réutiliser car la fonctionnalité «dépendante» est extrapolée dans des interfaces bien définies, permettant à des objets séparés dont la configuration est gérée par une plate-forme d'application appropriée d'être connectés à d'autres objets à volonté.
  2. Le code DI est beaucoup plus facile à tester. La fonctionnalité exprimée par l'objet peut être testée dans une boîte noire en construisant des objets «fictifs» implémentant les interfaces attendues par votre logique applicative.
  3. Le code DI est plus flexible. Il s'agit d'un code intrinsèquement faiblement couplé - à l'extrême. Cela permet au programmeur de choisir la manière dont les objets sont connectés en fonction exclusivement de leurs interfaces requises d'un côté et de leurs interfaces exprimées de l'autre.
  4. La configuration externe (Xml) des objets DI signifie que d'autres peuvent personnaliser votre code dans des directions imprévues.
  5. La configuration externe est également un modèle de séparation des préoccupations en ce que tous les problèmes d'initialisation d'objet et de gestion de l'interdépendance d'objet peuvent être traités par le serveur d'application.
  6. Notez que la configuration externe n'est pas nécessaire pour utiliser le modèle DI, pour les interconnexions simples, un petit objet constructeur est souvent adéquat. Il y a un compromis en matière de flexibilité entre les deux. Un objet générateur n'est pas une option aussi flexible qu'un fichier de configuration visible de l'extérieur. Le développeur du système DI doit peser les avantages de la flexibilité par rapport à la commodité, en veillant à ce que le contrôle à petite échelle et à grain fin de la construction d'objet tel qu'exprimé dans un fichier de configuration puisse augmenter la confusion et les coûts de maintenance sur toute la ligne.

Le code DI semble définitivement plus lourd, les inconvénients d'avoir tous ces fichiers XML qui configurent des objets à injecter dans d'autres objets semblent difficiles. C'est cependant le but des systèmes DI. Votre capacité à mélanger et à faire correspondre des objets de code sous la forme d'une série de paramètres de configuration vous permet de créer des systèmes complexes en utilisant du code tiers avec un codage minimal de votre part.

L'exemple fourni dans la question touche simplement à la surface de la puissance expressive qu'une bibliothèque d'objets DI correctement factorisée peut fournir. Avec un peu de pratique et beaucoup d'autodiscipline, la plupart des praticiens en DI trouvent qu'ils peuvent construire des systèmes qui ont une couverture de test à 100% du code d'application. Ce seul point est extraordinaire. Il ne s'agit pas d'une couverture de test à 100% d'une petite application de quelques centaines de lignes de code, mais d'une couverture de test à 100% d'applications comprenant des centaines de milliers de lignes de code. Je ne suis pas en mesure de décrire tout autre modèle de conception qui offre ce niveau de testabilité.

Vous avez raison en ce sens qu'une application de seulement 10 lignes de code est plus facile à comprendre que plusieurs objets plus une série de fichiers de configuration XML. Cependant, comme avec les modèles de conception les plus puissants, les gains sont constatés à mesure que vous continuez à ajouter de nouvelles fonctionnalités au système.

En bref, les applications basées sur DI à grande échelle sont à la fois plus faciles à déboguer et à comprendre. Bien que la configuration Xml ne soit pas «vérifiée au moment de la compilation», tous les services d'application dont cet auteur a connaissance fourniront au développeur des messages d'erreur s'ils tentent d'injecter un objet ayant une interface incompatible dans un autre objet. Et la plupart fournissent une fonction de «vérification» qui couvre toutes les configurations d'objets connus. Cela se fait facilement et rapidement en vérifiant que l'objet A à injecter implémente l'interface requise par l'objet B pour toutes les injections d'objets configurés.


4
comprendre les avantages de l'ID. Je ne comprends pas quels avantages sont ajoutés par la configuration XML externe par rapport à la configuration de code qui fait la même chose. Les avantages que vous avez mentionnés sont fournis par le modèle de conception DI. La question portait sur les avantages de la configuration DI par rapport au code d'initialisation simple.
Pavel Feldman le

> La configuration externe est aussi une séparation ... La séparation de configuration est le cœur de DI ce qui est bien. Et il peut dôme en utilisant le code d'initialisation. Qu'est-ce que cfg ajoute par rapport à l'initialisation du code? Pour moi, il semble que chaque ligne de cfg a une ligne de code d'initialisation correspondante.
Pavel Feldman le

7

C'est un peu une question chargée, mais j'ai tendance à convenir que d'énormes quantités de configuration xml ne représentent pas vraiment beaucoup d'avantages. J'aime que mes applications soient aussi légères que possible sur les dépendances, y compris les frameworks lourds.

Ils simplifient le code la plupart du temps, mais ils ont aussi une surcharge de complexité qui rend la recherche de problèmes assez difficile (j'ai vu de tels problèmes de première main, et Java simple avec lequel je serais beaucoup plus à l'aise).

Je suppose que cela dépend un peu du style, et de ce avec quoi vous êtes à l'aise ... aimez-vous piloter votre propre solution et avoir l'avantage de la connaître à fond, ou miser sur des solutions existantes qui peuvent s'avérer difficiles lorsque la configuration n'est pas t juste pas? C'est tout un compromis.

Cependant, la configuration XML est un peu une bête noire de la mienne ... J'essaye de l'éviter à tout prix.


5

Chaque fois que vous pouvez modifier votre code en données, vous faites un pas dans la bonne direction.

Coder quoi que ce soit sous forme de données signifie que votre code lui-même est plus général et réutilisable. Cela signifie également que vos données peuvent être spécifiées dans une langue qui leur correspond exactement.

En outre, un fichier XML peut être lu dans une interface graphique ou un autre outil et facilement manipulé de manière pragmatique. Comment feriez-vous cela avec l'exemple de code?

Je factorise constamment les choses que la plupart des gens implémenteraient sous forme de code dans les données, cela rend le code qui reste BEAUCOUP plus propre. Je trouve inconcevable que les gens créent un menu en code plutôt qu'en tant que données - il devrait être évident que le faire dans le code est tout simplement faux à cause du passe-partout.


a du sens, n'y a pas pensé dans cette perspective
Pavel Feldman

7
là encore, les gens vont souvent dans l'autre sens et essaient de mettre de la logique dans les données, ce qui signifie simplement que vous
finissez

@Casebash C'est un point de vue intéressant - je serais incroyablement intéressé par un exemple. Je trouve que tout ce que je peux déplacer dans les données aide. Je trouve également que si je fais exactement ce que vous dites, le langage est en fait amélioré parce que c'est un DSL - mais même dans ce cas, il faut une justification sérieuse pour créer un langage entièrement nouveau.
Bill K

1
"Chaque fois que vous pouvez modifier votre code en données, vous faites un pas dans la bonne direction." Bienvenue dans l'anti-pattern Soft Coding.
Raedwald

@Raedwald Ce dont vous parlez est l'externalisation, ce qui peut être très difficile si vous ne savez pas ce que vous faites (et la raison pour laquelle quelqu'un incompétent l'a essayé, a échoué et l'a appelé un anti-modèle) Des exemples plus positifs seraient l'injection, les itérateurs , presque tout ce qui a des annotations, tout ce qui s'initialise avec des tableaux. La plupart des grandes structures de programmation sont une tentative de séparer les différences dans votre code et de combiner ce qui reste, en le pilotant avec quelque chose qui peut être mieux regroupé et géré.
Bill K

3

La raison de l'utilisation d'un conteneur DI est que vous n'avez pas besoin d'avoir un milliard de propriétés préconfigurées dans votre code qui sont simplement des getters et des setters. Voulez-vous vraiment coder en dur tous ceux avec le nouveau X ()? Bien sûr, vous pouvez avoir une valeur par défaut, mais le conteneur DI permet la création de singletons, ce qui est extrêmement facile et vous permet de vous concentrer sur les détails du code, pas sur la tâche diverse de l'initialiser.

Par exemple, Spring vous permet d'implémenter l'interface InitializingBean et d'ajouter une méthode afterPropertiesSet (vous pouvez également spécifier une «méthode init» pour éviter de coupler votre code à Spring). Ces méthodes vous permettront de vous assurer que toute interface spécifiée en tant que champ dans votre instance de classe est correctement configurée au démarrage, et vous n'aurez plus à vérifier null vos getters et setters (en supposant que vous autorisez vos singletons à rester thread-safe ).

De plus, il est beaucoup plus facile de faire des initialisations complexes avec un conteneur DI au lieu de les faire vous-même. Par exemple, j'aide à utiliser XFire (pas CeltiXFire, nous n'utilisons que Java 1.4). L'application utilisait Spring, mais elle utilisait malheureusement le mécanisme de configuration services.xml de XFire. Lorsqu'une collection d'éléments avait besoin de déclarer qu'elle contenait ZERO ou plusieurs instances au lieu d'une ou plusieurs instances, je devais remplacer une partie du code XFire fourni pour ce service particulier.

Certaines valeurs par défaut de XFire sont définies dans son schéma Spring beans. Donc, si nous utilisions Spring pour configurer les services, les beans auraient pu être utilisés. Au lieu de cela, ce qui s'est passé, c'est que j'ai dû fournir une instance d'une classe spécifique dans le fichier services.xml au lieu d'utiliser les beans. Pour ce faire, j'avais besoin de fournir le constructeur et de configurer les références déclarées dans la configuration XFire. Le vrai changement que j'avais besoin de faire exigeait que je surcharge une seule classe.

Mais, grâce au fichier services.xml, j'ai dû créer quatre nouvelles classes, en définissant leurs valeurs par défaut en fonction de leurs valeurs par défaut dans les fichiers de configuration Spring de leurs constructeurs. Si nous avions pu utiliser la configuration Spring, j'aurais pu simplement dire:

<bean id="base" parent="RootXFireBean">
    <property name="secondProperty" ref="secondBean" />
</bean>

<bean id="secondBean" parent="secondaryXFireBean">
    <property name="firstProperty" ref="thirdBean" />
</bean>

<bean id="thirdBean" parent="thirdXFireBean">
    <property name="secondProperty" ref="myNewBean" />
</bean>

<bean id="myNewBean" class="WowItsActuallyTheCodeThatChanged" />

Au lieu de cela, cela ressemblait plus à ceci:

public class TheFirstPointlessClass extends SomeXFireClass {
    public TheFirstPointlessClass() {
        setFirstProperty(new TheSecondPointlessClass());
        setSecondProperty(new TheThingThatWasHereBefore());
    }
}

public class TheSecondPointlessClass extends YetAnotherXFireClass {
    public TheSecondPointlessClass() {
        setFirstProperty(TheThirdPointlessClass());
    }
}

public class TheThirdPointlessClass extends GeeAnotherXFireClass {
    public TheThirdPointlessClass() {
        setFirstProperty(new AnotherThingThatWasHereBefore());
        setSecondProperty(new WowItsActuallyTheCodeThatChanged());
    }
}

public class WowItsActuallyTheCodeThatChanged extends TheXFireClassIActuallyCareAbout {
    public WowItsActuallyTheCodeThatChanged() {
    }

    public overrideTheMethod(Object[] arguments) {
        //Do overridden stuff
    }
}

Le résultat net est donc que quatre classes Java supplémentaires, pour la plupart inutiles, ont dû être ajoutées à la base de code pour obtenir l'effet qu'une classe supplémentaire et des informations de conteneur de dépendances simples ont obtenu. Ce n'est pas "l'exception qui prouve la règle", c'est la règle ... gérer les bizarreries dans le code est beaucoup plus propre lorsque les propriétés sont déjà fournies dans un conteneur DI et que vous les modifiez simplement pour s'adapter à une situation particulière, ce qui arrive le plus souvent.


3

J'ai ta réponse

Il y a évidemment des compromis dans chaque approche, mais les fichiers de configuration XML externalisés sont utiles pour le développement d'entreprise dans lequel les systèmes de construction sont utilisés pour compiler le code et non votre IDE. En utilisant le système de construction, vous voudrez peut-être injecter certaines valeurs dans votre code - par exemple la version de la construction (ce qui pourrait être pénible d'avoir à mettre à jour manuellement à chaque fois que vous compilez). La douleur est plus grande lorsque votre système de construction extrait le code d'un système de contrôle de version. La modification de valeurs simples au moment de la compilation vous obligerait à modifier un fichier, à le valider, à le compiler, puis à revenir à chaque fois pour chaque modification. Ce ne sont pas des modifications que vous souhaitez valider dans votre contrôle de version.

Autres cas d'utilisation utiles concernant le système de construction et les configurations externes:

  • injecter des styles / feuilles de style pour une seule base de code pour différentes versions
  • injecter différents ensembles de contenu dynamique (ou des références à ceux-ci) pour votre base de code unique
  • injection de contexte de localisation pour différents builds / clients
  • modification d'un URI de service Web en serveur de sauvegarde (lorsque le principal tombe en panne)

Mise à jour: Tous les exemples ci-dessus concernaient des éléments qui ne nécessitaient pas nécessairement de dépendances sur les classes. Mais vous pouvez facilement créer des cas où un objet complexe et une automatisation sont nécessaires - par exemple:

  • Imaginez que vous disposiez d'un système dans lequel il surveillait le trafic de votre site Web. En fonction du nombre d'utilisateurs simultanés, il active / désactive un mécanisme de journalisation. Peut-être que pendant que le mécanisme est désactivé, un objet stub est mis à sa place.
  • Imaginez que vous disposiez d'un système de conférence Web dans lequel, selon le nombre d'utilisateurs, vous souhaitiez désactiver la possibilité de faire du P2P en fonction du nombre de participants.

+1 pour mettre en évidence l'aspect entreprise en haut. Tester un code hérité mal écrit peut parfois être un cauchemar de plusieurs jours.
Richard Le Mesurier

2

Vous n'avez pas besoin de recompiler votre code chaque fois que vous modifiez quelque chose dans la configuration. Cela simplifiera le déploiement et la maintenance du programme. Par exemple, vous pouvez échanger un composant avec un autre avec seulement 1 changement dans le fichier de configuration.


déploiement? probablement ... maintien du déploiement? probablement ... maintenance du code? J'ai tendance à penser que non ... le débogage via des frameworks a tendance à être un gros casse-tête, et les pojos sont beaucoup plus faciles à gérer à cet égard.
Mike Stone

1
Mike, je n'ai rien dit sur le code. Nous savons tous que la configuration XML est nul :)
aku

Hmm ... à quelle fréquence changez-vous de composants sans recompiler et pourquoi? Je comprends que si quelqu'un modifie les informations d'identification de la base de données et ne veut pas recompiler le programme - ce n'est peut-être pas lui qui le développe. Mais je peux à peine imaginer quelqu'un d' autre que la configuration du ressort de changement de développeur
Pavel Feldman

Pavel, généralement, cette situation se produit lorsque vous devez déployer un programme sur des centaines de clients. Dans une telle situation, il est beaucoup plus facile de modifier la configuration que de déployer une nouvelle version du produit. Vous avez raison de dire à propos des développeurs. Habituellement, le développeur crée un nouveau cfg et l'administrateur le déploie.
aku

2

Vous pouvez insérer une nouvelle implémentation pour petite amie. Ainsi, une nouvelle femelle peut être injectée sans recompiler votre code.

<bean id="jane" class="foo.bar.HotFemale">
  <property name="age" value="19"/>
</bean>
<bean id="mary" class="foo.bar.Female">
  <property name="age" value="23"/>
</bean>
<bean id="john" class="foo.bar.Male">
  <property name="girlfriend" ref="jane"/>
</bean>

(Ce qui précède suppose que Female et HotFemale implémentent la même interface GirlfFriend)


Pourquoi les modifications logiques sans recompilation sont-elles considérées comme une bonne idée?
Pavel Feldman le

Je peux certainement faire HotFemale jane = new HotFmale (); jane.setAge (19); john.setGirlfriend (jane); Donc, la seule différence est que cfg peut être modifié sans recompilation? Cela semble être une réponse courante lorsque l'on discute du printemps. Pourquoi?! Pourquoi est-il bon d'éviter de compiler?
Pavel Feldman

Eh bien, je peux mieux tester le code, je peux Mock the Female Object.
Paul Whelan

@ Pavel Feldman: parce que si vous avez déjà déployé l'application chez le client, c'est plus facile.
Andrei Rînea

1

Dans le monde .NET, la plupart des frameworks IoC fournissent à la fois une configuration XML et Code.

StructureMap et Ninject, par exemple, utilisent des interfaces fluides pour configurer les conteneurs. Vous n'êtes plus obligé d'utiliser des fichiers de configuration XML. Spring, qui existe également dans .NET, repose fortement sur les fichiers XML car il s'agit de son interface de configuration principale historique, mais il est toujours possible de configurer des conteneurs par programme.


C'est génial que je puisse enfin utiliser le code pour ce qu'il était destiné à être utilisé :) Mais pourquoi ai-je même besoin de quelque chose d'autre qu'un langage de programmation pour faire de telles choses?
Pavel Feldman le

Je pense que c'est parce que XML permet des modifications d'exécution, ou du moins, des modifications de configuration sans avoir à recompiler le projet.
Romain Verdier

1

Facilité de combiner des configurations partielles en une configuration finale complète.

Par exemple, dans les applications Web, le modèle, la vue et les contrôleurs sont généralement spécifiés dans des fichiers de configuration distincts. Utilisez l'approche déclarative, vous pouvez charger, par exemple:

  UI-context.xml
  Model-context.xml
  Controller-context.xml

Ou charger avec une interface utilisateur différente et quelques contrôleurs supplémentaires:

  AlternateUI-context.xml
  Model-context.xml
  Controller-context.xml
  ControllerAdditions-context.xml

Faire la même chose dans le code nécessite une infrastructure pour combiner des configurations partielles. Pas impossible à faire dans le code, mais certainement plus facile à faire en utilisant un framework IoC.


1

Souvent, le point important est de savoir qui modifie la configuration après l'écriture du programme. Avec la configuration dans le code, vous supposez implicitement que la personne qui le change a les mêmes compétences et accès au code source, etc. que l'auteur d'origine.

Dans les systèmes de production, il est très pratique d'extraire un sous-ensemble de paramètres (par exemple, l'âge dans votre exemple) dans un fichier XML et de permettre par exemple à l'administrateur système ou au personnel d'assistance de modifier la valeur sans leur donner le plein pouvoir sur le code source ou d'autres paramètres - ou simplement pour les isoler des complexités.


C'est un point valable, mais la configuration du ressort a souvent tendance à être assez complexe. Bien qu'il soit facile de changer d'âge, l'administrateur système doit toujours gérer un gros fichier XML qu'il ne comprend pas nécessairement entièrement. N'est-il pas préférable d'extraire une partie qui est censée être configurée dans quelque chose d'encore plus simple, que la configuration XML Spring? Comme le fichier de propriétés, avec une seule ligne "age = 23" et ne laissez pas l'administrateur modifier d'autres détails, comme les noms de classe, etc., qui nécessitent une connaissance de la structure interne du programme.
Pavel Feldman

Je travaillais récemment sur un projet qui avait un mélange de code Java et XSLT. L'équipe était un mélange de personnes qui étaient fortes en Java (et peut-être moins à l'aise avec XML et XSLT); et les personnes qui travaillaient très fort avec XML et XSLT (et moins à l'aise avec Java). Comme la configuration allait être gérée par le deuxième groupe, il était logique d'utiliser Spring et d'avoir des configurations XML. En d'autres termes, Spring a résolu un problème de division du travail dans l'équipe. Cela n'a pas résolu un problème «technique»; dans le sens où la configuration aurait tout aussi bien pu être réalisée avec du code Java.
Dawood ibn Kareem

Quand le «personnel de support» saurait-il quelque chose sur la nécessité de modifier certaines classes créées dans un conteneur d'injection de dépendances Vraiment en supposant que c'est le travail d'un développeur de faire cela?
Jimbo

C'est exactement la raison pour laquelle l'extraction des valeurs de configuration (par exemple l'URL du système avec lequel vous intégrez) a du sens: le personnel de support édite le fichier de propriétés ou (dans le pire des cas) le fichier XML, la classe Java compilée reste la même.
Miro A.

1

Du point de vue du printemps, je peux vous donner deux réponses.

Premièrement, la configuration XML n'est pas le seul moyen de définir la configuration. La plupart des choses peuvent être configurées à l'aide d'annotations et les choses qui doivent être faites avec XML sont la configuration du code que vous n'écrivez pas de toute façon, comme un pool de connexions que vous utilisez à partir d'une bibliothèque. Spring 3 inclut une méthode pour définir la configuration DI à l'aide de Java similaire à la configuration DI roulée à la main dans votre exemple. Donc, utiliser Spring ne signifie pas que vous devez utiliser un fichier de configuration basé sur XML.

Deuxièmement, Spring est bien plus qu'un simple framework DI. Il possède de nombreuses autres fonctionnalités, notamment la gestion des transactions et l'AOP. La configuration Spring XML mélange tous ces concepts. Souvent, dans le même fichier de configuration, je spécifie des dépendances de bean, des paramètres de transaction et j'ajoute des beans à portée de session qui géraient réellement l'utilisation d'AOP en arrière-plan. Je trouve que la configuration XML offre un meilleur endroit pour gérer toutes ces fonctionnalités. Je pense également que la configuration basée sur les annotations et la configuration XML évoluent mieux que la configuration basée sur Java.

Mais je comprends votre point de vue et il n'y a rien de mal à définir la configuration d'injection de dépendances en Java. Je le fais normalement moi-même dans les tests unitaires et lorsque je travaille sur un projet suffisamment petit pour que je n'ai pas ajouté de framework DI. Je ne spécifie normalement pas la configuration en Java parce que pour moi, c'est le genre de code de plomberie que j'essaie d'éviter d'écrire lorsque j'ai choisi d'utiliser Spring. C'est une préférence cependant, cela ne signifie pas que la configuration XML est supérieure à la configuration basée sur Java.


0

Spring a également un chargeur de propriétés. Nous utilisons cette méthode pour définir des variables dépendant de l'environnement (ex: développement, test, acceptation, production, ...). Cela peut être par exemple la file d'attente à écouter.

S'il n'y a aucune raison pour laquelle la propriété changerait, il n'y a pas non plus de raison de la configurer de cette manière.


0

Votre cas est très simple et n'a donc pas besoin d'un conteneur IoC (Inversion of Control) comme Spring. D'un autre côté, lorsque vous "programmez sur des interfaces, pas sur des implémentations" (ce qui est une bonne pratique en POO), vous pouvez avoir un code comme celui-ci:

IService myService;
// ...
public void doSomething() {
  myService.fetchData();
}

(notez que le type de myService est IService - une interface, pas une implémentation concrète). Désormais, il peut être pratique de laisser votre conteneur IoC fournir automatiquement l'instance concrète correcte d'IService lors de l'initialisation - lorsque vous avez de nombreuses interfaces et de nombreuses implémentations, il peut être fastidieux de le faire manuellement. Les principaux avantages d'un conteneur IoC (framework d'injection de dépendances) sont:

  • Configuration externe du mappage entre les interfaces et leurs implémentations concrètes
  • Le conteneur IoC gère certains problèmes délicats tels que la résolution de graphiques de dépendances complexes, la gestion de la durée de vie des composants, etc.
  • Vous gagnez du temps de codage car vous fournissez des mappages de manière déclarative, pas dans un code procédural
  • Le principe d'inversion du contrôle permet des tests unitaires faciles car vous pouvez remplacer les implémentations réelles par de fausses (comme le remplacement d'une base de données SQL par une base de données en mémoire)

0

L'initialisation dans un fichier de configuration XML simplifiera votre travail de débogage / d'adaptation avec un client qui a déployé votre application sur ses ordinateurs. (Parce qu'il ne nécessite pas de recompilation + remplacement de fichiers binaires)


-2

L'une des raisons les plus attrayantes est le " principe hollywoodien ": ne nous appelez pas, nous vous appellerons. Un composant n'est pas obligé d'effectuer lui-même les recherches vers d'autres composants et services; au lieu de cela, ils lui sont fournis automatiquement. En Java, cela signifie qu'il n'est plus nécessaire d'effectuer des recherches JNDI à l'intérieur du composant.

Il est également beaucoup plus facile de tester un composant isolément: au lieu de lui donner une implémentation réelle des composants dont il a besoin, vous utilisez simplement des simulations (éventuellement générées automatiquement).


Cette réponse concerne l'injection de dépendances. Je sais ce que c'est, je sais que c'est bien et je le dis clairement dans la première phrase de la question. La question portait sur les avantages de la configuration DI, par rapport au code d'initialisation simple.
Pavel Feldman le

Ne répond pas vraiment à la question
Casebash
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.