7
votes

Est-il mauvais d'utiliser une serveuse au lieu de l'injection constructrice afin d'éviter d'écrire des charges de classes d'usine

En ce moment, nous utilisons DI / IOC et lorsque nous devons passer des paramètres supplémentaires à un constructeur, nous utilisons une classe d'usine, par exemple

public class EmailSender 
{
    public class Factory
    {
        ILogger emailLogger;
        public Factory(ILogger emailLogger)
        { 
            this.emailLogger = emailLogger;
        }
        public EmailSender Create(string toEmail, string subject, string body) 
        {
            return new EmailSender(toEmail, subject, body, emailLogger);
        }
    }
    private EmailSender(string toEmail, string subject,String body, ILogger emailLogger)
    {
    } 
}


3 commentaires

Merci d'avoir posté des modifications, je trouve ce processus de pensée très utile car je pense à travers les mêmes défis.


C'est une excellente question et une excellente question que je ne pense pas a été vraiment répondue correctement ci-dessous. Peut-être que je manque quelque chose, mais je n'ai vu que des solutions qui vous permettent de définir des paramètres de constructeur supplémentaires de manière centralisée de manière centralisée de manière centralisée que la résolution des interfaces de manière centralisée est effectuée. C'est une situation très différente de celle décrite ci-dessus, où vous souhaitez pouvoir utiliser le CTOR avec des paramètres comme d'habitude, mais profitez également de découpler l'objet ILogger. Je ne peux que supposer que ce type d'utilisation rend ces scénarios inappropriés pour DI avec CTORS.


J'ai l'impression que la forme DI de CIO devrait vraiment être réservée aux véritables "composants de service" qui ne nécessitent pas de configuration dans la manière dont vous souhaitez le faire ci-dessus. Cela dit, je serais ravi d'être montré autrement! :)


3 Réponses :


14
votes

oui - c'est mauvais.

  • Pourquoi écrire tout ce code quand vous pouvez avoir le cadre faire le travail? Tous les appels ioc.Resolve () sont superflu et vous ne devriez pas avoir à écrivez-les.
  • Un autre aspect encore plus important, est que vos composants sont liés à votre localisateur de services.

    Vous êtes maintenant incapable de les instantiez comme ça - tu as besoin d'un Complètement configurez le localisateur de services dans placer chaque fois que vous devez utiliser un composant.

  • dernier mais, bot le moins - votre code SL est saupoudré sur votre codebase ce qui n'est pas une bonne chose, parce que Quand tu veux changer quelque chose, Vous devez regarder dans plusieurs endroits.

9 commentaires

L'écriture 'x = ioc.Resolve ()' Le problème de code est un non-question pour moi - cela me permet d'écrire une charge de classes d'usine. Le problème de devoir changer mon code SL ou à lier à une mise en œuvre est assez mineur également - surtout si j'utilise CODEPLEX .Com / CommonServiceLocator . Le pire point est que le composant est lié à une SL particulière, ce qui signifie qu'un appelant ne pouvait pas changer les dépendances, donc je vais l'accepter comme meilleure réponse.


Vous n'avez pas à écrire des cours d'usine! Conteneur IOC est un seul configurable UberFactory et si vous structurez correctement votre code, tout ce dont vous avez besoin.


Et vous souhaitez tirer des services de certaines usines vous-même (et vous utilisez Windsor), vous pouvez toujours utiliser une installation TypeFactory qui mettra en œuvre votre usine sauvegardée par le conteneur CastleProject.org/Container/facitiers/v1rc3/typedFactory/... ou autogène CODE.GOOGE.COM/P/castleAutogen


Dans la situation détaillée ci-dessus, vous avez des paramètres qui doivent être transmis au temps de création (corps, à, sujet). Sans une classe d'usine explicite, vous vous retrouvez avec des chaînes magiques comme noms de paramètres.


Que vous pouvez utiliser les installations que je vous ai donné des liens ci-dessus. Cependant, je pense que tu le fais mal. J'aurais juste avoir un corps d'Iemailervice et passer du corps, sous réserve de paramètre à sa méthode , laissant les détails de la mise en œuvre encapsulés, sa mise en œuvre est gratuite pour nouveau dans le courrier électronique ou tout ce qui est nécessaire à l'intérieur, et I En tant qu'utilisateur, je suis blindé de ces détails de mise en œuvre. De plus, je n'ai besoin d'aucune usine pour le faire, profiter des avantages de l'inversion du contrôle


Dans ce cas, je suggère que vous suggère de ressembler beaucoup à une usine pour moi! L'exemple ci-dessus était destiné à être représentatif d'une classe immuable de quelque nature que ce soit, nécessite des paramètres du constructeur. Ma question, plus précise est retraitée, devient "dans la situation que vous avez une classe immuable, qui prend des paramètres non connus tant que le temps de création et certains qui sont enregistrés dans un conteneur DI, et que vous ne voulez pas avoir de chaînes magiques dans CodeBase *, est-il correct d'utiliser des appels en ligne vers un SL pour éviter les coûts d'écriture des usines ". * A par produit d'usines de réception automatique


et bien non. Je pense toujours que c'est un problème avec votre conception. Pouvez-vous montrer plus de scénario de vie réel? Pourquoi avez-vous besoin de cette classe pour être immuable? Emainservices.Sendemail (Toemail, Sujet, Corps); <- C'est comme ça que je le ferais. Pas besoin de SL ici.


Peut-être que chacun des courriels est une entité et je dois persister ce que j'ai envoyé à des fins de rapport? Je pense que nous avons passé un peu loin avec cette discussion, je pense que je devrais arrêter de poster des QS théoriques!


Oui, nous dérivons :) Quoi qu'il en soit, il est généralement possible (et préféré) de s'efforcer d'atteindre l'indépendance SL. Dans votre échantillon, je ne voudrais certainement pas persister mon message électronique au même endroit qui l'envoie! De toute façon bonne chance :)




1
votes

Je ne suis pas tout à fait sûr de ce fort "c'est mauvais" réponse donnée par Krzysztof. Je pense qu'il y a un peu de compromis et de préférence là-bas sans les classer absolument comme mauvais ou bon.

  • Je ne pense pas qu'il soit plus superflu qui écrit ces ioc.Resolve () que d'écrire des constructeurs spécifiques ou des propriétés pour le mécanisme d'injection.
  • Celui-ci, je dois accepter que vous soyez lié à un localisateur de services et que vous devez le mettre en place avant d'instancer une classe. Pourtant:
    • Vous pouvez séparer votre localisateur de service avec des interfaces plus spécifiques. Réduisant ainsi le couplage avec un énorme localisateur de services pour chaque service de votre système
    • Ouais, si vous utilisez un Mécanisme di, vous supprimerez tous ceux ioc.Resolve (), mais vous devrez toujours utiliser une sorte de conteneur pour instancier vos services "principaux". Le di doit intercepter ces appels, non?
    • Votre localisateur de services pourrait (devrait?) être "configurable auto-configurable" ou au moins, assez facile à configurer.
    • Voir ci-dessus le "séparer votre localisateur de service avec des interfaces plus spécifiques ..." Point.

      Je pense que l'utilisation d'un localisateur de services cachent effectivement vos dépendances à l'intérieur de la classe au lieu de les exposer à travers des constructeurs. Et c'est un inconvénient à mon avis parce que vous ne saurez pas que votre classe manque quelque chose jusqu'à ce que le localisateur de services soit appelé sans être configuré.

      Mais la chose di chose n'est pas libre de ce genre de noir de l'obscurité. Lorsque vous utilisez DI, il n'est vraiment pas évident de comprendre comment ces dépendances ne sont que «apparues» (DI Magic) dans votre constructeur. En utilisant un SL, vous pouvez au moins voir où ces dépendances viennent.

      Mais toujours, lorsque vous testez une classe qui expose ces dépendances sur ses constructeurs, vous ne pouvez pas le manquer. Ce n'est pas le cas à l'aide d'un localisateur de service.

      Je ne dis pas que Krzysztof était faux, car je suis d'accord avec lui pour le plus. Mais je suis sûr que l'utilisation d'un localisateur de service n'est pas nécessairement une mauvaise "conception" et certainement pas tout simplement mal.

      phil


1 commentaires

Lorsque vous regardez cela du point de vue de la migration d'une base de code héritée vers (éventuellement) à l'aide de DI, il s'agit peut-être d'un outil (temporaire) qui peut être utilisé en cours de route?