[dependency-injection] Pourquoi utilise-t-on l'injection de dépendance?



Answers

Je pense que les gens sont souvent déconcertés par la différence entre l' injection de dépendance et un framework d' injection de dépendance (ou un conteneur comme on l'appelle souvent).

L'injection de dépendance est un concept très simple. Au lieu de ce code:

public class A {
  private B b;

  public A() {
    this.b = new B(); // A *depends on* B
  }

  public void DoSomeStuff() {
    // Do something with B here
  }
}

public static void Main(string[] args) {
  A a = new A();
  a.DoSomeStuff();
}

vous écrivez du code comme ceci:

public class A {
  private B b;

  public A(B b) { // A now takes its dependencies as arguments
    this.b = b; // look ma, no "new"!
  }

  public void DoSomeStuff() {
    // Do something with B here
  }
}

public static void Main(string[] args) {
  B b = new B(); // B is constructed here instead
  A a = new A(b);
  a.DoSomeStuff();
}

Et c'est tout. Sérieusement. Cela vous donne une tonne d'avantages. Deux fonctions importantes sont la possibilité de contrôler la fonctionnalité à partir d'un emplacement central (la fonction Main() ) au lieu de la répartir dans votre programme et de tester plus facilement chaque classe isolément (car vous pouvez passer des simulacres ou d'autres objets truqués dans son constructeur au lieu d'une valeur réelle).

L'inconvénient, bien sûr, est que vous avez maintenant une méga-fonction qui connaît toutes les classes utilisées par votre programme. C'est ce que les frameworks DI peuvent aider. Mais si vous avez du mal à comprendre pourquoi cette approche est utile, je vous recommande de commencer par l'injection manuelle de dépendance, afin que vous puissiez mieux comprendre ce que les différents frameworks peuvent faire pour vous.

Question

J'essaie de comprendre les injections de dépendance (DI), et encore une fois j'ai échoué. Cela semble juste idiot. Mon code n'est jamais un gâchis; J'écris à peine des fonctions et des interfaces virtuelles (bien que je le fasse une fois dans une lune bleue) et toute ma configuration est magiquement sérialisée dans une classe en utilisant json.net (utilisant parfois un sérialiseur XML).

Je ne comprends pas très bien quel problème il résout. Cela ressemble à une façon de dire: "salut, quand vous exécutez cette fonction, renvoyez un objet de ce type et utilise ces paramètres / données."
Mais ... pourquoi utiliserais-je ça? Remarque: Je n'ai jamais eu besoin d'utiliser d' object , mais je comprends à quoi cela sert.

Quelles sont les situations réelles dans la construction d'un site Web ou d'une application de bureau où l'on pourrait utiliser DI? Je peux facilement trouver des cas pour lesquels quelqu'un voudra utiliser des interfaces / fonctions virtuelles dans un jeu, mais il est extrêmement rare (assez rare que je ne me souvienne pas d'une seule occurrence) de l'utiliser dans un code autre que le jeu.




Je pense que la réponse classique est de créer une application plus découplée, qui ne sait pas quelle implémentation sera utilisée pendant l'exécution.

Par exemple, nous sommes un fournisseur de services de paiement central, travaillant avec de nombreux fournisseurs de paiement dans le monde entier. Cependant, quand une demande est faite, je n'ai aucune idée du processeur de paiement que je vais appeler. Je pourrais programmer une classe avec une tonne de cas de commutation, tels que:

class PaymentProcessor{

    private String type;

    public PaymentProcessor(String type){
        this.type = type;
    }

    public void authorize(){
        if (type.equals(Consts.PAYPAL)){
            // Do this;
        }
        else if(type.equals(Consts.OTHER_PROCESSOR)){
            // Do that;
        }
    }
}

Maintenant, imaginez que maintenant vous devez conserver tout ce code dans une seule classe car il n'est pas découplé correctement, vous pouvez imaginer que pour chaque nouveau processeur que vous allez prendre en charge, vous devrez créer un nouveau cas if // switch pour chaque méthode, cela devient plus compliqué, cependant, en utilisant Dependency Injection (ou Inversion of Control - comme on l'appelle parfois, ce qui signifie que celui qui contrôle l'exécution du programme n'est connu qu'à l'exécution, et pas de complication), vous pourriez réaliser quelque chose très propre et maintenable.

class PaypalProcessor implements PaymentProcessor{

    public void authorize(){
        // Do PayPal authorization
    }
}

class OtherProcessor implements PaymentProcessor{

    public void authorize(){
        // Do other processor authorization
    }
}

class PaymentFactory{

    public static PaymentProcessor create(String type){

        switch(type){
            case Consts.PAYPAL;
                return new PaypalProcessor();

            case Consts.OTHER_PROCESSOR;
                return new OtherProcessor();
        }
    }
}

interface PaymentProcessor{
    void authorize();
}

** Le code ne compilera pas, je sais :)




Links