web-dev-qa-db-fra.com

Injection de dépendance vs modèle d'usine

La plupart des exemples cités pour l’utilisation de Dependency Injection peuvent également être résolus à l’aide du modèle d’usine. En ce qui concerne l’utilisation/la conception, la différence entre l’injection de dépendance et l’usine est floue ou mince.

Une fois, quelqu'un m'a dit que c'est la manière dont vous l'utilisez qui fait la différence!

Une fois, j’ai utilisé StructureMap un conteneur d’ID pour résoudre un problème, je l’ai ensuite reconçu pour fonctionner avec une fabrique simple et supprimé les références à StructureMap.

Quelqu'un peut-il me dire quelle est la différence entre eux et où utiliser quoi, quelle est la meilleure pratique ici?

478
Binoj Antony

Lorsque vous utilisez une usine, votre code est toujours en réalité responsable de la création d'objets. Par DI, vous externalisez cette responsabilité vers une autre classe ou un framework séparé de votre code.

284
willcodejavaforfood

Je suggérerais de garder les concepts clairs et simples. L'injection de dépendance est davantage un modèle architectural permettant de coupler de manière lâche des composants logiciels. Le modèle d'usine n'est qu'un moyen de séparer la responsabilité de la création d'objets d'autres classes vers une autre entité. Le modèle d'usine peut être appelé en tant qu'outil pour implémenter DI. L'injection de dépendance peut être mise en œuvre de plusieurs manières, par exemple, DI utilisant des constructeurs, mappant des fichiers XML, etc.

213
Perpetualcoder

Injection de dépendance

Au lieu d'instancier les pièces elles-mêmes, une voiture demande les pièces dont elle a besoin pour fonctionner.

class Car
{
    private Engine engine;
    private SteeringWheel wheel;
    private Tires tires;

    public Car(Engine engine, SteeringWheel wheel, Tires tires)
    {
        this.engine = engine;
        this.wheel = wheel;
        this.tires = tires;
    }
}

Usine

Rassemble les pièces pour former un objet complet et masque le type de béton de l'appelant.

static class CarFactory
{
    public ICar BuildCar()
    {
        Engine engine = new Engine();
        SteeringWheel steeringWheel = new SteeringWheel();
        Tires tires = new Tires();
        ICar car = new RaceCar(engine, steeringWheel, tires);
        return car;
    }   
}

Résultat

Comme vous pouvez le constater, les usines et DI se complètent.

static void Main()
{
     ICar car = CarFactory.BuildCar();
     // use car
}

Vous souvenez-vous de goldilocks et des trois ours? Eh bien, l'injection de dépendance est un peu comme ça. Voici trois façons de faire la même chose.

void RaceCar() // example #1
{
    ICar car = CarFactory.BuildCar();
    car.Race();
}

void RaceCar(ICarFactory carFactory) // example #2
{
    ICar car = carFactory.BuildCar();
    car.Race();
}

void RaceCar(ICar car) // example #3
{
    car.Race();
}

Exemple # 1 - C'est le pire, car il masque complètement la dépendance. Si vous considérez la méthode comme une boîte noire, vous n’auriez aucune idée qu’il fallait une voiture.

Exemple # 2 - C'est un peu mieux, car nous savons maintenant qu'il nous faut une voiture puisque nous passons dans une usine. Mais cette fois, nous passons trop, car tout ce dont nous avons besoin, c’est d’une voiture. Nous passons dans une usine uniquement pour construire la voiture, alors que la voiture pourrait être construite en dehors de la méthode et passée.

Exemple # 3 - C'est idéal car la méthode demande exactement quoi il faut. Pas trop ou trop peu. Je n'ai pas besoin d'écrire un MockCarFactory pour créer des MockCars, je peux passer le simulacre directement. C'est direct et l'interface ne ment pas.

Cette conversation Google Tech de Misko Hevery est incroyable et constitue la base de ce sur quoi je tire mon exemple. http://www.youtube.com/watch?v=XcT4yYu_TTs

174
Despertar

La raison pour laquelle l’injection de dépendance (DI) et les modèles d’usine sont similaires est qu’il s’agit de deux implémentations de Inversion of Control (IoC), une architecture logicielle. En termes simples, ce sont deux solutions au même problème.

Donc, pour répondre à la question, la principale différence entre le modèle Factory et DI est la manière dont la référence d'objet est obtenue. Avec dépendance comme son nom l'indique, la référence est injectée ou donnée à votre code. Avec le modèle d'usine, votre code doit demander la référence pour que votre code récupère l'objet. Les deux implémentations suppriment ou découplent le lien entre le code et la classe ou le type sous-jacent de la référence d'objet utilisée par le code.

Il convient de noter que les modèles Factory (ou même les modèles Abstract Factory, qui sont des usines renvoyant de nouvelles usines renvoyant des références d'objet) peuvent être écrits pour choisir dynamiquement ou être liés au type ou à la classe d'objet demandé au moment de l'exécution. Cela les rend très similaires (encore plus que DI) au modèle Service Locator, qui est une autre implémentation de l'IoC.

Le modèle de conception Factory est assez ancien (en termes de logiciel) et existe depuis un certain temps. Depuis la popularité récente du modèle architectural IoC, il fait un retour en force.

Je suppose qu'en ce qui concerne les modèles de conception d'IoC: les injecteurs injectent, les localisateurs localisent et les usines ont été restructurées.

42
Tom Maher

Il existe des problèmes qui sont faciles à résoudre avec l’injection de dépendance et qui ne sont pas aussi faciles à résoudre avec une série d’usines.

Une partie de la différence entre, d’une part, l’inversion de contrôle et l’injection de dépendance (IOC/DI), et, d’autre part, un localisateur de service ou un ensemble d’usines (factory), est la suivante:

IOC/DI est un écosystème complet d'objets et de services de domaine en soi. Il met tout en place pour vous dans la manière que vous spécifiez. Vos objets et services de domaine sont construits par le conteneur et ne se construisent pas eux-mêmes: ils n'ont donc pas de dépendances aucune sur le conteneur ni sur aucune fabrique. IOC/DI permet un degré de configuration extrêmement élevé, avec toute la configuration en un seul endroit (construction du conteneur) sur la couche la plus haute de votre application (l'interface graphique, l'interface Web).

Factory résume une partie de la construction de vos objets et services de domaine. Mais les objets et les services de domaine sont toujours chargés de déterminer comment se construire et comment obtenir tout ce dont ils dépendent. Toutes ces dépendances "actives" filtrent à travers toutes les couches de votre application. Il n'y a pas un seul endroit où tout configurer.

40
yfeldblum

Un inconvénient de DI est qu’elle ne peut pas initialiser des objets avec de la logique. Par exemple, lorsque je dois créer un personnage dont le nom et l'âge sont aléatoires, DI n'est pas le choix par rapport au modèle d'usine. Avec les usines, nous pouvons facilement encapsuler l'algorithme aléatoire depuis la création d'objet, qui prend en charge l'un des modèles de conception appelé "Encapsuler ce qui varie".

25
BinMaster

La gestion du cycle de vie est l’une des responsabilités assumées par les conteneurs de dépendance, en plus de l’instanciation et de l’injection. Le fait que le conteneur conserve parfois une référence aux composants après l'instanciation explique pourquoi il est appelé un "conteneur" et non une usine. Les conteneurs d'injection de dépendance ne contiennent généralement qu'une référence aux objets dont ils ont besoin pour gérer les cycles de vie, ou qui sont réutilisés pour de futures injections, tels que les singletons ou les poids massifs. Lorsqu'il est configuré pour créer de nouvelles instances de certains composants pour chaque appel au conteneur, ce dernier oublie généralement tout simplement l'objet créé.

De: http://tutorials.jenkov.com/dependency-injection/dependency-injection-containers.html

22
Pup

Je pense que DI est un type de couche d'abstraction sur les usines, mais ils offrent également des avantages au-delà de l'abstraction. Une vraie usine sait comment instancier un seul type et le configurer. Une bonne couche DI offre la possibilité, via la configuration, d’instancier et de configurer de nombreux types.

Évidemment, pour un projet comportant quelques types simples nécessitant une logique métier relativement stable dans la construction, le modèle d’usine est simple à comprendre, à mettre en œuvre et fonctionne bien.

OTOH, si vous avez un projet contenant de nombreux types dont l'implémentation est susceptible de changer souvent, DI vous donne la possibilité, grâce à sa configuration, de le faire au moment de l'exécution sans avoir à recompiler vos usines.

16
Will

Théorie

Il y a deux points importants à considérer:

  1. Qui crée des objets

    • [Factory]: Vous devez écrire un objet HOW doit être créé. Vous avez une classe Factory séparée contenant la logique de création.
    • [Injection de dépendance]: dans des cas pratiques, elle est réalisée par des cadres externes (par exemple, dans Java, ce serait spring/ejb/guice). L'injection se fait "magiquement" sans explicite la création de nouveaux objets
  2. Quel genre d'objets il gère:

    • [Usine]: habituellement responsable de la création d'objets avec état
    • [Injections de dépendance] Plus susceptibles de créer des objets sans état

Exemple pratique d'utilisation d'injection d'usine et de dépendance dans un seul projet

  1. Ce que nous voulons construire

Module d'application permettant de créer une commande contenant plusieurs entrées appelées orderline.

  1. Architecture

Supposons que nous voulions créer l'architecture de couche suivante:

enter image description here

Les objets de domaine peuvent être des objets stockés dans la base de données. Le référentiel (DAO) facilite la récupération des objets de la base de données. Le service fournit une API à d'autres modules. Alows pour les opérations sur le module order

  1. Domaine Layer et utilisation des usines

Les entités qui figureront dans la base de données sont Order et OrderLine. L'ordre peut avoir plusieurs lignes de commande. Relationship between Order and OrderLine

Vient maintenant une partie importante de la conception. Les modules extérieurs à celui-ci doivent-ils créer et gérer eux-mêmes des lignes de commande? La ligne de commande ne doit exister que lorsque vous avez associé une commande à celle-ci. Il serait préférable de cacher la mise en œuvre interne à des classes extérieures.

Mais comment créer Order sans connaître les OrderLines?

Usine

Quelqu'un qui souhaite créer un nouvel ordre a utilisé OrderFactory (qui masquera des détails sur le fait que nous créons un ordre).

enter image description here

C’est comme ça que ça va se passer dans IDE. Les classes en dehors du paquet domain utiliseront OrderFactory au lieu de constructeur à l'intérieur de Order

  1. Injection de dépendance L'injection de dépendance est plus couramment utilisée avec des couches sans état telles que référentiel et service.

OrderRepository et OrderService sont gérés par l'infrastructure d'injection de dépendance. Le référentiel est responsable de la gestion des opérations CRUD sur la base de données. Le service injecte le référentiel et l'utilise pour enregistrer/trouver les classes de domaine correctes.

enter image description here

13
Marcin Szymczak

Je sais que cette question est ancienne, mais je voudrais ajouter mes cinq cents,

Je pense que l'injection de dépendance (DI) ressemble à bien des égards à un modèle d'usine configurable (FP), et dans ce sens, tout ce que vous pourriez faire avec DI vous permettra de le faire avec une telle usine.

En fait, si vous utilisez Spring par exemple, vous avez la possibilité d’utiliser des ressources de câblage automatique (DI) ou de faire quelque chose comme ceci:

MyBean mb = ctx.getBean("myBean");

Et ensuite, utilisez cette instance de "mb" pour faire n'importe quoi. N'est-ce pas un appel à une usine qui vous renverra une instance?

La seule différence réelle que je remarque entre la plupart des exemples FP est que vous pouvez configurer le nom "myBean" dans une classe xml ou une autre, et qu'un cadre fonctionnera en usine, mais ce n'est pas le cas la même chose, et vous pouvez certainement avoir une Factory qui lit un fichier de configuration ou obtient l’implémentation selon ses besoins.

Et si vous me demandez mon avis (et je sais que vous ne l'avez pas fait), je pense que DI fait la même chose mais ajoute simplement plus de complexité au développement, pourquoi?

tout d’abord, pour que vous sachiez quelle est l’implémentation utilisée pour tout haricot que vous filez automatiquement avec DI, vous devez accéder à la configuration elle-même.

mais ... qu'en est-il de cette promesse que vous n'aurez pas à connaître l'implémentation de l'objet que vous utilisez? pfft! sérieusement? quand vous utilisez une approche comme celle-ci ... n'êtes-vous pas le même qui écrit l'implémentation? et même si vous ne le faites pas, ne regardez-vous pas presque tout le temps la mise en œuvre de ce qu'elle est censée faire?

et pour une dernière chose, peu importe ce que promet un framework DI vous allez construire des choses découplées à partir de là, sans dépendance à leurs classes, si vous utilisez un cadre, vous construisez tout ce qui y est, si vous devez changer l'approche ou le cadre, ce ne sera pas une tâche facile ... JAMAIS! ... mais, puisque vous construisez tout autour de cela cadre particulier au lieu de vous soucier de la meilleure solution pour votre entreprise, vous serez confronté à un problème de taille lorsque vous le ferez.

En fait, la seule application métier réelle pour une approche FP ou DI est celle que je peux voir, si vous devez modifier les implémentations utilisées à runtime, mais au moins les frameworks I sachez que vous ne le permettez pas, vous devez tout laisser parfait dans la configuration au moment du développement et si vous avez besoin d’une autre approche.

Donc, si j'ai une classe qui fonctionne différemment dans deux portées dans la même application (disons, deux sociétés d'un holding), je dois configurer le cadre pour créer deux beans différents et adapter mon code pour les utiliser. N'est-ce pas la même chose que si j'écrivais quelque chose comme ceci:

MyBean mb = MyBeanForEntreprise1(); //In the classes of the first enterprise
MyBean mb = MyBeanForEntreprise2(); //In the classes of the second enterprise

le même que celui-ci:

@Autowired MyBean mbForEnterprise1; //In the classes of the first enterprise
@Autowired MyBean mbForEnterprise2; //In the classes of the second enterprise

Et ça:

MyBean mb = (MyBean)MyFactory.get("myBeanForEntreprise1"); //In the classes of the first enterprise
MyBean mb = (MyBean)MyFactory.get("myBeanForEntreprise2"); //In the classes of the second enterprise

Dans tous les cas, vous devrez modifier quelque chose dans votre application, qu'il s'agisse de classes ou de fichiers de configuration, mais vous devrez le redéployer.

Ne serait-il pas agréable de faire quelque chose comme ceci:

MyBean mb = (MyBean)MyFactory.get("mb"); 

Et de cette façon, vous définissez le code de l’usine pour obtenir la bonne implémentation au moment de l’exécution en fonction de l’entreprise d’utilisateur enregistré. Maintenant, cela serait utile. Vous pouvez simplement ajouter un nouveau fichier jar avec les nouvelles classes et définir les règles peut-être même au moment de l'exécution (ou ajouter un nouveau fichier de configuration si vous laissez cette option ouverte), sans modification des classes existantes. Ce serait une usine dynamique!

cela ne serait-il pas plus utile que de devoir écrire deux configurations pour chaque entreprise, et peut-être même avoir deux applications différentes pour chaque ??

Vous pouvez me dire que je n'ai pas besoin de faire le commutateur au moment de l'exécution. Je configure donc l'application. Si j'hérite de la classe ou utilise une autre implémentation, je modifie simplement la configuration et le redéploie. Ok, cela peut aussi être fait avec une usine. Et soyez honnête, combien de fois faites-vous cela? peut-être que si vous avez une application qui va être utilisée quelque part dans votre entreprise et que vous allez transmettre le code à une autre équipe, qui réalisera des choses comme celle-ci. Mais bon, cela peut aussi être fait avec l'usine, et serait encore mieux avec une usine dynamique !!

Quoi qu'il en soit, la section commentaire si ouverte pour que vous me tuez.

12
Frank Orellana

La COI est un concept qui est mis en œuvre de deux manières. Création de dépendance et injection de dépendance, Factory/Abstract Factory sont l'exemple de la création de dépendance. L'injection de dépendance est constructeur, opérateur et interface. Le coeur de IOC est de ne pas dépendre des classes concrètes, mais de définir l’abstrait des méthodes (par exemple une classe Interface/abstract) et de l’utiliser pour appeler la méthode de la classe concrète. Comme modèle d'usine, retourne la classe de base ou l'interface. De même, l’injection de dépendance utilise la classe/interface de base pour définir la valeur des objets.

6
Thakur

Avec l'injection de dépendance, le client n'a pas besoin d'obtenir ses dépendances, il est tout préparé à l'avance.

Avec les usines, quelqu'un doit les appeler pour amener les objets générés à l'endroit où ils sont nécessaires.

La différence réside principalement dans cette seule ligne où l’appel de la fabrique et la récupération de l’objet construit sont effectuées.

Mais avec les usines, vous devez écrire cette ligne partout où vous avez besoin d’un tel objet. Avec DI, il vous suffit de créer le câblage (relation entre l’utilisation et l’objet créé) une fois et de vous fier ensuite à la présence de l’objet partout. De l’autre côté, l’ID nécessite souvent un peu plus (ce qui dépend du cadre) du travail de préparation.

5
Kosi2801

Vous pouvez consulter ce lien pour une comparaison des deux approches (et d'autres) dans un exemple réel.

En gros, lorsque les exigences changent, vous modifiez davantage de code si vous utilisez des usines au lieu de DI.

Ceci est également valable avec DI manuel (c’est-à-dire qu’il n’existe pas de framework externe fournissant les dépendances à vos objets, mais que vous les transmettez dans chaque constructeur).

3

J'ai eu la même question dès que j'ai lu sur DI et que je me suis retrouvé à ce poste. Donc finalement c'est ce que j'ai compris mais corrigez-moi s'il vous plaît.

"Il y a longtemps, il y avait des petits royaumes avec leurs propres organes de gouvernement contrôlant et prenant leurs décisions en se basant sur leurs propres règles écrites. Ils ont ensuite formé un grand gouvernement qui élimine tous ces petits organes de gouvernement qui ne possèdent qu'un ensemble de règles (constitution) et sont mis en œuvre par des tribunaux"

Les organes directeurs des petits royaumes sont des "usines"

Le grand gouvernement est "l'injecteur de dépendance".

3
blueskin

je crois que DI est un moyen de configurer ou d’instantaliser un haricot. La DI peut être réalisée de différentes manières, comme constructeur, setter-getter, etc.

Le motif d'usine n'est qu'un autre moyen d'instancier les haricots. ce modèle sera utilisé principalement lorsque vous devez créer des objets à l'aide du modèle de conception d'usine, car lors de l'utilisation de ce modèle, vous ne configurez pas les propriétés d'un bean, vous ne faites qu'instancier l'objet.

Vérifiez ce lien: Injection de dépendance

2
harshit

Binoj,

Je ne pense pas que vous devez choisir l'un sur l'autre.

Le fait de déplacer une classe ou une interface dépendante vers un constructeur ou un séparateur de classe suit le modèle DI. L'objet que vous transmettez au constructeur ou à l'ensemble peut être implémenté avec Factory.

Quand utiliser? Utilisez le ou les modèles qui se trouvent dans votre timonerie de développeur. Avec quoi se sentent-ils le plus à l'aise et le plus facile à comprendre.

2
Jason Slocomb

Je crois que 3 aspects importants régissent les objets et leur utilisation:
1. Instanciation (d'une classe avec initialisation éventuelle).
2. Injection (de l'instance ainsi créée) là où c'est nécessaire.
3. Gestion du cycle de vie (de l'instance ainsi créée).

En utilisant le modèle d’usine, le premier aspect (instanciation) est obtenu, mais les deux derniers sont discutables. La classe qui utilise d'autres instances doit coder en dur les usines (au lieu d'instances en cours de création), ce qui empêche des capacités de couplage lâches. En outre, gestion du cycle de vie des instances devient un défi dans une grande application où une usine est utilisée à plusieurs endroits (en particulier, si l'usine ne gère pas le cycle de vie de l'instance qu'elle renvoie, elle obtient laid).

En revanche, en utilisant un DI (de motif IoC), les 3 sont abstraits en dehors du code (dans le conteneur DI) et le bean géré n’a besoin de rien de cette complexité. Loose Coupling, un objectif architectural très important peut être atteint confortablement. Un autre objectif architectural important, le séparation des préoccupations peut être atteint bien mieux que les usines.

Alors que les usines peuvent convenir à de petites applications, les plus grandes préfèrent choisir DI plutôt que des usines.

2
Anand Vemula

La plupart des réponses ici expliquent la différence conceptuelle et les détails de mise en œuvre des deux. Cependant, je n’ai pas pu trouver d’explication sur la différence d’application qui est l’OMI la plus importante et le PO a demandé. Alors laissez-moi rouvrir ce sujet ...

Une fois, quelqu'un m'a dit que c'est la manière dont vous l'utilisez qui fait la différence!

Exactement. Dans 90% des cas, vous pouvez obtenir une référence d'objet en utilisant soit Factory soit DI, et vous vous retrouvez généralement avec cette dernière. Dans 10% des cas, utiliser Factory est seule manière correcte. Ces cas incluent l’obtention d’objets par variable selon les paramètres d’exécution. Comme ça:

IWebClient client = factoryWithCache.GetWebClient(url: "stackoverflow.com",
        useCookies: false, connectionTimeout: 120);

Dans ce cas, obtenir client à partir de DI n'est pas possible (ou nécessite au moins une solution de contournement laide). Donc, en règle générale, pour prendre une décision: si une dépendance peut être obtenue sans aucun paramètre calculé au moment de l'exécution, alors DI est préférable, sinon utilisez Factory.

1
neleus

Modèle de conception d'usine

Le modèle de conception d’usine est caractérisé par

  • Une interface
  • Cours d'implémentation
  • Une usine

Vous pouvez observer peu de choses quand vous vous questionnez comme ci-dessous

  • Quand la fabrique créera-t-elle un objet pour les classes d'implémentation - exécution ou heure de compilation?
  • Et si vous voulez changer d'implémentation au moment de l'exécution? - pas possible

Celles-ci sont traitées par injection de dépendance.

injection de dépendance

Vous pouvez avoir différentes façons d'injecter une dépendance. Pour plus de simplicité, allons avec Interface Injection

Dans DI, container crée les instances nécessaires et les "injecte" dans l'objet.

Ainsi élimine l'instanciation statique.

Exemple:

public class MyClass{

  MyInterface find= null;

  //Constructor- During the object instantiation

  public MyClass(MyInterface myInterface ) {

       find = myInterface ;
  }

  public void myMethod(){

       find.doSomething();

  }
}

Avec une fabrique, vous pouvez regrouper les interfaces associées. Ainsi, si les paramètres passés peuvent être groupés dans une fabrique, c’est aussi une bonne solution pour constructor overinjection regardez ce code *):

public AddressModelFactory(IAddressAttributeService addressAttributeService,
        IAddressAttributeParser addressAttributeParser,
        ILocalizationService localizationService,
        IStateProvinceService stateProvinceService,
        IAddressAttributeFormatter addressAttributeFormatter)
    {
        this._addressAttributeService = addressAttributeService;
        this._addressAttributeParser = addressAttributeParser;
        this._localizationService = localizationService;
        this._stateProvinceService = stateProvinceService;
        this._addressAttributeFormatter = addressAttributeFormatter;
    }

Regardez le constructeur, il vous suffit de passer la IAddressModelFactory ici, donc moins de paramètres *):

 public CustomerController(IAddressModelFactory addressModelFactory,
        ICustomerModelFactory customerModelFactory,
        IAuthenticationService authenticationService,
        DateTimeSettings dateTimeSettings,
        TaxSettings taxSettings,
        ILocalizationService localizationService,
        IWorkContext workContext,
        IStoreContext storeContext,
        ICustomerService customerService,
        ICustomerAttributeParser customerAttributeParser,
        ICustomerAttributeService customerAttributeService,
        IGenericAttributeService genericAttributeService,
        ICustomerRegistrationService customerRegistrationService,
        ITaxService taxService,
        CustomerSettings customerSettings,
        AddressSettings addressSettings,...

Vous voyez dans CustomerController beaucoup de paramètres passés, Oui, vous pouvez le voir comme constructor overinjection mais c'est comme ça que DI fonctionne. Et non, rien ne va pas avec le CustomerController.

*) Le code provient de nopCommerce.

1

Mes pensées:

Dependecy Injection: transmettez les collaborateurs en tant que paramètres aux constructeurs. Dependency Injection Framework: une fabrique générique et configurable pour créer les objets à transmettre en tant que paramètres aux constructeurs.

1
bloparod

En termes simples, la méthode d’injection de dépendance par rapport à l’usine implique respectivement un mécanisme push-pull.

mécanisme Pull: les classes ont indirectement une dépendance à la méthode Factory qui à leur tour dépend de classes concrètes.

mécanisme de poussée: Le composant racine peut être configuré avec tous les composants dépendants dans un emplacement unique, favorisant ainsi une maintenance élevée et un couplage lâche.

Avec la méthode Factory, la responsabilité incombe toujours à la classe (bien qu'indirectement) de créer un nouvel objet où, comme pour l'injection de dépendance, cette responsabilité est externalisée (au prix d'une fuite d'abstraction).

1
Rahul Agarwal

Un cadre d'injection est une implémentation du modèle d'usine.

Tout dépend de vos besoins. Si vous avez besoin d'implémenter le modèle d'usine dans une application, il est fort probable que l'une des innombrables implémentations d'infrastructure d'injection répondra à vos besoins.

Vous ne devez déployer votre propre solution que si vos exigences ne peuvent être satisfaites par aucun des cadres tiers. Plus vous écrivez de code, plus vous avez de code à gérer. Le code est un passif et non un atout.

Les arguments sur l'implémentation que vous devez utiliser ne sont pas aussi fondamentaux que la compréhension des besoins architecturaux de votre application.

1
Mick

À partir d'une valeur faciale, ils ont le même aspect

En termes très simples, Factory Pattern, un modèle de création nous aide à créer un objet - "Définir une interface pour la création d’un objet". Si nous avons un type de valeur de clé de pool d’objets (par exemple, Dictionnaire), en transmettant la clé à la fabrique (je fais référence au modèle de fabrique simple), vous pouvez résoudre le type. Travail accompli! Le cadre d'injection de dépendance (tel que Structure Map, Ninject, Unity ... etc) semble en revanche faire la même chose.

Mais ... "Ne réinventez pas la roue"

D'un point de vue architectural, c'est une couche de liaison et "Ne réinventez pas la roue".

Pour une application de niveau entreprise, le concept de DI est plutôt une couche architecturale qui définit des dépendances. Pour simplifier cela davantage, vous pouvez considérer cela comme un projet classlibrary séparé, qui résout les dépendances. L'application principale dépend de ce projet où le résolveur de dépendance fait référence à d'autres implémentations concrètes et à la résolution des dépendances.

En plus de "GetType/Create" depuis une fabrique, nous avons le plus souvent besoin de plus de fonctionnalités (possibilité d'utiliser XML pour définir des dépendances, moquages ​​et tests unitaires, etc.). Puisque vous avez fait référence à Structure Map, regardez la liste de fonctions Structure Map . C'est clairement plus que résoudre le mappage d'objet simple. Ne réinventez pas la roue!

Si tout ce que vous avez est un marteau, tout ressemble à un clou

Selon vos besoins et le type d'application que vous construisez, vous devez faire un choix. S'il ne comporte que peu de projets (peut-être un ou deux ..) et implique peu de dépendances, vous pouvez choisir une approche plus simple. C'est comme si vous utilisiez ADO .Net pour l'accès aux données via Entity Framework pour des appels simples à une ou deux bases de données, l'introduction d'EF étant excessive dans ce scénario.

Mais pour un projet plus important ou si votre projet s'agrandit, je vous recommande vivement de disposer d'une couche DI avec un cadre et de laisser de la place pour changer le cadre DI que vous utilisez (Utiliser une façade dans l'application principale (Web App, Web Api, Desktop). ..etc.).

1
Dhanuka777

Je pense que ceux-ci sont orthogonaux et peuvent être utilisés ensemble. Laissez-moi vous montrer un exemple que j'ai rencontré récemment au travail:

Nous utilisions le framework Spring dans Java pour DI. Une classe singleton (Parent) devait instancier de nouveaux objets d'une autre classe (Child), et ceux-ci avaient des collaborateurs complexes:

@Component
class Parent {
    // ...
    @Autowired
    Parent(Dep1 dep1, Dep2 dep2, ..., DepN depN) {
        this.dep1 = dep1;
        this.dep2 = dep2;
    }

    void method(int p) {
        Child c = new Child(dep1, dep2, ..., depN, p);
        // ...
    }
}

Dans cet exemple, Parent doit recevoir des instances de DepX uniquement pour les transmettre au constructeur Child. Problèmes avec ceci:

  1. Parent a plus de connaissances sur Child qu'il ne le devrait
  2. Parent a plus de collaborateurs qu'il ne devrait
  3. Ajouter des dépendances à Child implique de changer Parent

C'est à ce moment que j'ai réalisé qu'une Factory conviendrait parfaitement ici:

  1. Il cache tout sauf les vrais paramètres de la classe Child, vue par Parent
  2. Il résume la connaissance de la création d'une Child, qui peut être centralisée dans la configuration DI.

Il s'agit de la classe Parent simplifiée et de la classe ChildFactory:

@Component
class Parent {
    // ...
    @Autowired
    Parent(ChildFactory childFactory) {
        this.childFactory = childFactory;
    }

    void method(int p) {
        Child c = childFactory.newChild(p);
        // ...
    }
}

@Component
class ChildFactory {
    // ...
    @Autowired
    Parent(Dep1 dep1, Dep2 dep2, ..., DepN depN) {
        this.dep1 = dep1;
        this.dep2 = dep2;
        // ...
        this.depN = depN;
    }

    Child newChild(int p) {
        return new Child(dep1, dep2, ..., depN, p);
    }
}
0
Martín Coll