Méthode de fabrique avec du DI et du Cio
Je suis familier avec ces modèles, mais ne sais toujours pas comment gérer la situation suivante:
public class CarFactory
{
public CarFactory(Dep1,Dep2,Dep3,Dep4,Dep5,Dep6)
{
}
public ICar CreateCar(type)
{
switch(type)
{
case A:
return new Car1(Dep1,Dep2,Dep3);
break;
case B:
return new Car2(Dep4,Dep5,Dep6);
break;
}
}
}
En général le problème est avec la quantité de références qui doit être injectée. Ce sera encore pire quand il y a plus de voitures.
Première approche qui me vient à l'esprit est d'injecter de Car1 et les personnages car2 dans l'usine du constructeur, mais il est contre l'approche parce que l'usine sera de retour toujours le même objet. La deuxième approche consiste à injecter servicelocator mais c'est antipattern partout. Comment le résoudre?
Edit:
Alternative 1:
public class CarFactory
{
public CarFactory(IContainer container)
{
_container = container;
}
public ICar CreateCar(type)
{
switch(type)
{
case A:
return _container.Resolve<ICar1>();
break;
case B:
return _container.Resolve<ICar2>();
break;
}
}
}
Alternative 2 (trop difficile à utiliser en raison d'un trop grand nombre de dépendances dans l'arbre):
public class CarFactory
{
public CarFactory()
{
}
public ICar CreateCar(type)
{
switch(type)
{
case A:
return new Car1(new Dep1(),new Dep2(new Dep683(),new Dep684()),....)
break;
case B:
return new Car2(new Dep4(),new Dep5(new Dep777(),new Dep684()),....)
break;
}
}
}
- Une pensée rapide est de faire un mappage de classe qui prend un
type
en entrée et retourne les troisDep#
vous avez besoin. Alors vous pouvez mapper toutes les dépendances, dans une instance de la cartographie de la classe dans le programme d'amorçage, puis injecter la cartographie de l'instance dans l'usine. - Je pense qu'il n'y a rien de mal avec
Alternative way 1
que vous avez montré lors de la mise en œuvre de cette usine appartient àComposition Root
. De ne pas vous inscrire DI conteneur lui-même dans le conteneur d'injection de dépendances - Que voulez-vous dire qu'il appartient à la Composition de la Racine? Pourriez-vous donner quelques exemples de code?
- La Composition de la Racine est l'endroit où vous vous reliez votre demande de conteneur d'injection de dépendances. Ainsi, par exemple, cela peut être un
Bootstrap
classe.
Vous devez vous connecter pour publier un commentaire.
Avoir un commutateur cas énoncé à l'intérieur d'une usine est une odeur de code. Fait intéressant, vous ne semblez pas être en se concentrant sur la résolution de cette question à tous.
Le meilleur, le plus DI solution à l'amiable pour ce scénario est le modèle de stratégie. Il permet à votre DI conteneur à injecter les dépendances dans l'usine les cas où ils appartiennent, sans encombrer les autres classes avec ces dépendances ou de recourir à un service de localisation.
Interfaces
Usines
Stratégie
Utilisation
Notez que parce qu'il n'y a pas d'interrupteur instruction du cas, vous pouvez ajouter d'autres usines de la stratégie sans modification de la conception, et chacune de ces usines peuvent avoir leurs propres dépendances qui sont injectés par le conteneur d'injection de dépendances.
new
opérateur sur le reste du code de l'isoler, le rendant DI sympathique. De ce fait, il faiblement couplés à partir du code qui utilise l'usine. Il n'est pas nécessaire que vous devez aller vers le conteneur pour résoudre l'instance - en fait, ce sera d'effectuer beaucoup plus rapide que d'utiliser le conteneur. Cela dit, l'injection du récipient dans l'abstract factory est une technique commune de permettre 3ème parties à intégrer à un cadre à l'aide de DI.Create(Type)
j'aiCreate(SomeEnum)
. La chose qui m'inquiète, c'est que cela semble à présent indésirables inconnus condition préalable lors de l'appel de Créer. Si j'ajoute un élément à laenum SomeEnum
sans ajouter le correspondant de l'usine un client pourrait appelerCreate(SomeEnum.SomeNewValue)
et provoquer une exception de violation d'encapsulation comme indiqué ici blog.ploeh.dk/2015/10/26/service de localisation-viole-encapsulationenum
pour la stratégie de sélection. Pas seulement parce qu'il violait l'encapsulation, mais lorsque vous utilisezenum
le code a changer dans 2 endroits différents lors de l'ajout d'un nouveau service de la stratégie. Si vous regardez à la mise en œuvre ci-dessus, à la fois de la logique sur la façon de sélectionner l'usine et la mise en œuvre de l'usine sont dans la même classe. Vous pouvez en ajouter ou en supprimer, sans changer aucune autre classe. Aussi, avec une légère modification, vous pourriez faire une stratégie d'exécuter plusieurs opérations à partir d'un ensemble beaucoup plus volumineux que dans cet exemple.System.Type
dans cet exemple parce que c'est plus le long des lignes de ce que vous attendez lors de l'utilisation d'un localisateur de service et l'OP a eu le type de pratique à sélectionner avec.enum
est un non-starter car il automatiquement traîne dans un indésirable type de la dépendance et la dépendance va dans les deux sens depuis l'enum est susceptible d'avoir des éléments qui ne sont pas inscrits auprès de la stratégie.Pour répondre à votre commentaire sur le code exemple avec
Composition Root
.Vous pouvez créer suivantes et ce n'est pas un Service Locator.
et voilà comment regarder vos
Composition Root
à l'aide de l'Unité DI conteneur :J'ai répondu à une question similaire il y a quelques temps. Fondamentalement, il est tout au sujet de votre choix. Vous avez à choisir entre le niveau de verbosité (ce qui vous donne plus de l'aide d'un compilateur et de l'automatisation, qui permet d'écrire moins de code, mais c'est plus sujette aux bugs.
Cette est ma réponse soutenir le niveau de verbosité.
Et cette est également une bonne réponse qui prend en charge l'automatisation.
MODIFIER
Je crois que l'approche que vous envisagez de mal, c'est vraiment le meilleur. Vérité être dit, d'habitude il n'y aura pas donc nombreuses dépendances, là. J'aime cette approche parce que c'est très explicite et rarement des résultats des erreurs d'exécution.
Celui-ci est mauvais. C'est en fait un localisateur de service, qui est considéré comme un anti-modèle.
Comme vous avez écrit, il n'est pas facile à utiliser si elle est mélangée avec du CIO containter. Toutefois, dans certains cas, une approche similaire (pauvre homme DI) peut être utile.
Dans l'ensemble, je n'aurais pas pris la peine de les avoir "beaucoup" de dépendances dans vos usines. C'est un simple déclarative code. Il faut quelques secondes pour écrire et peut vous épargner des heures de lutte avec des erreurs d'exécution.
Je voudrais envisager de donner les dépendances d'une bonne structure, de sorte que vous pouvez utiliser quelque chose de similaire à Wiktor réponse, mais je voudrais résumé de la Voiture de l'usine elle-même. Ensuite, vous n'utilisez pas le cas..alors la structure.
Je n'ai pas de liste, mais vous pouvez mettre en œuvre plusieurs types de voitures et des usines et l'utiliser DI pour injecter tout ce dont vous avez besoin.
Tout d'abord, vous avez une usine de béton, un conteneur IoC pourrait être une alternative plutôt que quelque chose à vous y aider.
Ensuite, il suffit de refactoriser l'usine pour ne pas attendre à une possible liste des paramètres de l'usine du constructeur. C'est la principale question - pourquoi êtes-vous en passant donc de nombreux paramètres si la méthode n'a pas besoin d'eux?
Je préfère passer des paramètres spécifiques à la méthode de
En encapsulant la liste des paramètres dans une classe spécifique, il suffit de rendre le client fournit exactement ces paramètres qui sont nécessaires pour les usines de l'invocation de méthode.
Edit:
Malheureusement, il n'était pas clair à partir de votre post, ce sont ces
Dep1
, ... et comment vous les utilisez.Je suggère la démarche suivante puis qui sépare l'usine fournisseur de usine réelle mise en œuvre. Cette approche est connue sous le Usine Locale modèle:
L'usine elle-même n'a pas toute la mise en œuvre, il est là pour poser les fondations de votre domaine d'API, où vous voulez que votre voiture instances être créés avec cette API uniquement.
Puis, dans la Composition de la Racine (quelque part près du point de départ de l'application, où vous configurez votre conteneur réel), vous pouvez configurer le fournisseur de:
Notez que dans cet exemple de mise en œuvre de l'usine du fournisseur utilise un délégué, mais une interface peut également être utilisé comme un cahier des charges d'un fournisseur réel.
Cette mise en œuvre est essentiellement #1 de votre édité question, cependant, il n'a pas tout particulier inconvénients. Le client appelle encore:
De nombreuses DI conteneurs de soutenir la notion de nommé dépendances.
E. g. (Structuremap syntaxe)
Si vous utilisez quelque chose comme une convention, une règle de la façon dont le nom est dérivé du béton du type de la voiture elle-même, vous avez une situation où vous n'avez pas besoin de toucher à l'usine plus lorsque vous étendez le système.
À l'aide de cette dans une usine est simple.