3
votes

Devrions-nous toujours créer des instances si nous voulons profiter de l'injection de dépendances?

J'approfondis le concept d'injection de dépendance et plus je lis, plus j'aime l'idée derrière cela. Je l'utilise depuis un certain temps déjà, mais encore beaucoup de choses me déroutent de temps en temps, et j'ai l'impression que je n'utilise pas tout son potentiel.

Imaginez le code ci-dessous. Dans cette classe, (probablement quelques choses peuvent être améliorées mais ..) nous avons une méthode qui renvoie une valeur de chaîne. Il n'y a pas besoin d'injection de constructeur (ou du moins c'est ce que je pense, corrigez-moi si je me trompe), mais à la dernière ligne du bloc try , nous créons une nouvelle instance de la classe StreamReader pour pouvoir transmettre la réponse stream vers lui et pour obtenir le résultat à l'aide de la méthode ReadToEnd .

L'idée derrière l'injection de dépendances est d'éviter de créer des instances à l'intérieur d'une classe, mais comment gérer ce scénario?

public class WebClientService : IWebClientService
{    
        public async Task<String> GetApiResponseAsync(string Url)
        {
            String responseText = await Task.Run(() =>
            {
                try
                {
                    HttpWebRequest request = WebRequest.Create(Url) as HttpWebRequest;
                    WebResponse response = request.GetResponse();
                    Stream responseStream = response.GetResponseStream();
                    return new StreamReader(responseStream).ReadToEnd();
                }
                catch (Exception e)
                {
                    LogMessageDispatcher.Instance.Log(e);
                }
                return null;
            });

            return responseText;
        }
}

Je passe en revue «le livre de Mark Seemann - Dependency Injection», mais j'ai encore beaucoup à couvrir.


2 commentaires

@ mark-sembleenn: J'apprécierais beaucoup si je pouvais avoir votre opinion à ce sujet. -Il y a probablement d'autres scénarios similaires qui me dérangent, donc quiconque essaie de répondre, veuillez ne pas me donner d'autres approches ou me conseiller d'utiliser différentes bibliothèques pour faire la requête Http. -A la place, proposez-moi une solution qui gardera la même approche - en utilisant le HttpWebRequest ... Cela m'aidera à comprendre la relation DI de mon problème et de la solution.


Veuillez lire Dans quelles circonstances puis-je ajouter des expressions «urgentes» ou d'autres expressions similaires à ma question, afin d'obtenir des réponses plus rapides? - le résumé est que ce n'est pas une manière idéale de s'adresser aux volontaires, et est probablement contre-productif pour obtenir des réponses. Veuillez ne pas l'ajouter à vos questions.


3 Réponses :


4
votes

C'est un exemple très trivial et relativement facile à définir car votre couplage est une classe de base sans aucune fonctionnalité liée au service. Commençons par la définition de DI dans wikipedia:

En génie logiciel, l'injection de dépendances est une technique par laquelle un objet fournit les dépendances d'un autre objet. Une «dépendance» est un objet qui peut être utilisé, par exemple en tant que service. Au lieu qu'un client spécifie quel service il utilisera, quelque chose indique au client quel service utiliser. L '"injection" fait référence au passage d'une dépendance (un service) à l'objet (un client) qui l'utiliserait. Le service fait partie de l'état du client. [1] Passer le service au client, plutôt que permettre à un client de créer ou de trouver le service, est l'exigence fondamentale du modèle.

Mais qu'est-ce que cela signifie Ne devrions-nous jamais créer un objet StringBuilder lorsque nous utilisons DI? La réponse est non (ou mieux encore pas toujours). Puis-je créer un nouveau flotteur sans DI? Serait-il judicieux de créer un service de création et de créer le StreamReader à partir de là?

Vous verrez que StreamReader est une public class StreamReader : System.IO.TextReader implémentation très basique public class StreamReader : System.IO.TextReader et les classes public class StreamReader : System.IO.TextReader même aucune autre interface que IDisposable. Vous ne pouvez pas sérieusement envisager d'injecter StreamReader pour IDisposable dans n'importe quelle classe.

Si vous souhaitez vous déconnecter de StreamReader cela signifie que vous voudrez peut-être utiliser autre chose à l'avenir. Vous pouvez créer un StreamService et créer votre flux comme vous le souhaitez, mais à la fin de la journée, StreamService aurait le couplage car StreamReader ne peut pas être injecté.

C'est pourquoi wikipedia en déduit que les services sont injectés. Les objets peuvent être découplés, mais vous pouvez utiliser d'autres modèles comme Factory .

Par ailleurs, utilisez StreamReader toujours avec le mot clé Using afin que l'objet puisse être correctement éliminé.


0 commentaires

2
votes

L'injection de dépendance est puissante sur certains points

  1. Test: le découplage est essentiel pour les tests unitaires et DI est le bon moyen d'y parvenir afin que vous puissiez avoir une interface et plusieurs implémentations et en fonction de ce que vous voulez, vous pouvez écrire un test unitaire pour votre code et injecter une classe concrète spécifique.

  2. Contrôle de la création d'objets: il vous permet de contrôler la manière dont les objets (spécifiques) sont créés et la durée de vie de vos objets.

Il faut donc savoir au début

  1. Quel type de classes et d'interfaces souhaitez-vous centraliser / contrôler la création de leurs objets?
  2. Quelle est la fonctionnalité selon laquelle, si des modifications lui sont apportées à l'avenir, vous souhaitez que votre code continue de fonctionner sans gros changements?
  3. Dans votre cas, vous utilisez StreamReader, c'est une classe intégrée en C #, vous devez donc penser à combien de fois je vais utiliser cette classe dans mon code? Dois-je le changer à l'avenir?

Si j'étais toi, je penserai à deux options

  1. Je ne me soucie pas de StreamReader, c'est une classe intégrée en C #, cela fonctionne bien et je ne vais pas écrire de test unitaire pour tester la fonctionnalité StreamReader, je vais donc l'utiliser comme ce que vous avez fait dans votre exemple de code.

  2. J'utilise StreamReader à de nombreux endroits dans le code et j'ai une logique répétée que j'avais l'habitude de faire à chaque fois après la lecture de stream, donc je vais créer l'interface IStreamReader avec les principales méthodes que je veux utiliser, puis utiliser la DI pour injecter le béton la mise en oeuvre.

Remarque : en utilisant DI, vous n'allez pas injecter tous les objets de votre système.


0 commentaires

1
votes

L'idée derrière l'injection de dépendances est d'éviter de créer des instances à l'intérieur d'une classe, mais comment gérer ce scénario?

Ce n'est pas du tout le but. L'un des points centraux de la DI est de permettre un couplage lâche aux dépendances volatiles . Tous les types dont dépend une classe ne sont pas volatils . Certains sont stables et il n'est pas nécessaire d'empêcher la création de dépendances stables à partir d'une classe. Le premier chapitre sur l'Injection de dépendances dans .NET et son successeur Principes, pratiques et modèles d'injection de dépendances contient une description détaillée de ce que sont les dépendances volatiles et stables et en quoi elles diffèrent.

La principale question que vous devez vous poser est de savoir si l'un des types dont dépend WebClientService est ou non des dépendances volatiles. La réponse dépend de votre contexte particulier, et vous devriez être en mesure de le comprendre après (re) lecture du chapitre 1.


1 commentaires

Merci pour votre réponse. J'ai aussi deux autres réponses assez descriptives. J'ai lu quelque part quelque chose du genre `` Quand on essaie d'appliquer parfaitement une solution particulière (d'un modèle ou d'un principe nouvellement appris), généralement, au début, il aggravera les choses d'environ 30 à 35% alors ce qu'elles seraient sans le modèle. :) Quoi qu'il en soit, je comprends votre point de vue et en effet je reviens sur le chapitre 1.