Quelle est la différence entre le modèle de stratégie et l'injection de dépendance?


95

Le modèle de stratégie et l'injection de dépendances nous permettent tous deux de définir / injecter des objets au moment de l'exécution. Quelle est la différence entre le modèle de stratégie et l'injection de dépendance?


Le modèle de stratégie pourrait utiliser l'injection de dépendance
TechWisdom

Réponses:


107

DI et Strategy fonctionnent de la même manière, mais Strategy est utilisé pour des dépendances plus fines et de courte durée.

Lorsqu'un objet est configuré avec une stratégie "fixe", par exemple lors de la construction de l'objet, la distinction entre stratégie et DI s'estompe. Mais dans un scénario DI, il est plus inhabituel que les dépendances des objets changent au cours de leur durée de vie, alors que ce n'est pas rare avec Strategy.

En outre, vous pouvez transmettre des stratégies en tant qu'arguments aux méthodes, alors que le concept associé d'injection d'arguments de méthode n'est pas répandu et principalement utilisé dans le contexte des tests automatisés uniquement.

La stratégie se concentre sur l'intention et vous encourage à créer une interface avec différentes implémentations qui obéissent au même contrat comportemental. DI consiste plus simplement à implémenter un comportement et à le fournir.

Avec DI, vous pouvez décomposer votre programme pour d'autres raisons que simplement pour pouvoir échanger des parties de l'implémentation. Une interface utilisée en DI avec une seule implémentation est très courante. Une «stratégie» avec une seule mise en œuvre concrète (jamais) n'est pas un réel problème mais est probablement plus proche de l'ID.


Une interface utilisée en DI avec une seule implémentation est très courante - alors qu'est-ce que DI dans ce cas particulier?
Kalpesh Soni du

3
Cette citation explique en gros tout:in a DI scenario it is more unusual that the dependencies of objects change during their lifetimes, while this is not uncommon with Strategy
Sergey Telshevsky

Stratégie: les classes sont conçues pour pouvoir être configurées avec un algorithme au moment de l'exécution. DI: De telles classes reçoivent un algorithme (un objet Strategy) injecté au moment de l'exécution. À partir de la mémoire GoF Design Patterns sur w3sdesign.com .
GFranke

39

La différence est ce qu'ils essaient de réaliser. Le modèle de stratégie est utilisé dans les situations où vous savez que vous souhaitez échanger des implémentations. Par exemple, vous souhaiterez peut-être formater les données de différentes manières - vous pouvez utiliser le modèle de stratégie pour échanger un formateur XML ou CSV, etc.

L'injection de dépendances est différente en ce que l'utilisateur n'essaye pas de modifier le comportement d'exécution. En suivant l'exemple ci-dessus, nous pourrions créer un programme d'exportation XML qui utilise un formateur XML. Plutôt que de structurer le code comme ceci:

public class DataExporter() {
  XMLFormatter formatter = new XMLFormatter();
}

vous `` injecteriez '' le formateur dans le constructeur:

public class DataExporter {
  IFormatter formatter = null;

  public DataExporter(IDataFormatter dataFormatter) {
    this.formatter = dataFormatter;
  }
}

DataExporter exporter = new DataExporter(new XMLFormatter());

Il existe quelques justifications à l'injection de dépendances, mais la principale est le test. Vous pourriez avoir un cas où vous avez un moteur de persistance d'une certaine sorte (comme une base de données). Cependant, il peut être pénible d'utiliser une vraie base de données lorsque vous exécutez des tests à plusieurs reprises. Donc, pour vos cas de test, vous injecteriez une base de données factice, de sorte que vous n'encourriez pas cette surcharge.

En utilisant cet exemple, vous pouvez voir la différence: nous prévoyons toujours d'utiliser une stratégie de stockage de données, et c'est celle que nous transmettons (la véritable instance de base de données). Cependant, en développement et en test, nous voulons utiliser différentes dépendances, donc nous injectons différentes concrétions.


28

Vous pouvez utiliser DI comme modèle de stratégie, vous pouvez donc permuter l'algorithme nécessaire pour chaque client, mais DI peut aller au-delà car c'est un moyen de simplement découpler les parties d'une application, qui ne feraient pas partie de le modèle de stratégie.

Il serait risqué de dire que l'ID n'est qu'un modèle de stratégie renommé car cela commence à diluer à quoi sert vraiment le modèle de stratégie, l'OMI.


2
Je pense que je comprends votre sens, mais je ne peux pas le mettre en mots correctement ... Donc, vous dites que DI est plus un modèle de mise en œuvre tandis que la stratégie est plus un modèle de conception, et une façon de mettre en œuvre la stratégie est par DI?
Robert Gould

1
Cela semble être une bonne façon de le dire. DI est plus qu'un simple modèle de stratégie. J'ai trouvé la même confusion avec AOP, où les gens pensent que c'est un modèle d'usine. Je pense que DI peut mettre en œuvre le modèle de stratégie, donc votre reformulation semble fantastique. :)
James Black

15

Mec, l'injection de dépendances est un modèle plus général, et il s'agit de la dépendance à des abstractions et non à des concrétions et cela fait partie de chaque modèle, mais le modèle de stratégie est une solution à un problème plus spécifique

c'est la définition de wikipedia:

DI:

L'injection de dépendances (DI) dans la programmation informatique orientée objet est un modèle de conception avec un principe fondamental de séparation du comportement de la résolution des dépendances. En d'autres termes: une technique de découplage de composants logiciels très dépendants.

Modèle de stratégie:

Dans la programmation informatique, le modèle de stratégie (également connu sous le nom de modèle de politique) est un modèle de conception de logiciel particulier, dans lequel des algorithmes peuvent être sélectionnés au moment de l'exécution.

Le modèle de stratégie est destiné à fournir un moyen de définir une famille d'algorithmes, d'encapsuler chacun d'eux en tant qu'objet et de les rendre interchangeables. Le modèle de stratégie permet aux algorithmes de varier indépendamment des clients qui les utilisent.


3
J'aime particulièrement la partie "mec" dans votre explication. :-)
johey

7

Les stratégies sont des choses de plus haut niveau qui sont utilisées pour changer la façon dont les choses sont calculées. Avec l'injection de dépendances, vous pouvez non seulement changer la façon dont les choses sont calculées, mais également ce qui est là.

Pour moi, cela devient clair lors de l'utilisation de tests unitaires. Pour l'exécution du code de production, vous avez toutes les données cachées (c'est-à-dire privées ou protégées); alors que, avec les tests unitaires, la plupart des données sont publiques afin que je puisse les regarder avec les Asserts.


Exemple de stratégie:

public class Cosine {
  private CalcStrategy strat;

  // Constructor - strategy passed in as a type of DI
  public Cosine(CalcStrategy s) {
    strat = s;
  }
}

public abstract class CalcStrategy {
  public double goFigure(double angle);
}

public class RadianStrategy extends CalcStrategy {
  public double goFigure(double angle) {
    return (...);
  }
}
public class DegreeStrategy extends CalcStrategy {
  public double goFigure(double angle) {
    return (...);
  }
}

Notez qu'il n'y a pas de données publiques différentes entre les stratégies. Il n'y a pas non plus de méthodes différentes. Les deux stratégies partagent toutes les mêmes fonctions et signatures.


Maintenant pour l'injection de dépendances:

public class Cosine {
  private Calc strat;

  // Constructor - Dependency Injection.
  public Cosine(Calc s) {
    strat = s;
  }
}

public class Calc {
  private int numPasses = 0;
  private double total = 0;
  private double intermediate = 0;

  public double goFigure(double angle) {
    return(...);
}

public class CalcTestDouble extends Calc {
  // NOTICE THE PUBLIC DATA.
  public int numPasses = 0;
  public double total = 0;
  public double intermediate = 0;
  public double goFigure(double angle) {
    return (...);
  }
}

Utilisation:

public CosineTest {

  @Test
  public void testGoFigure() {
    // Setup
    CalcTestDouble calc = new CalcTestDouble();
    Cosine instance = new Cosine(calc);

    // Exercise
    double actualAnswer = instance.goFigure(0.0);

    // Verify
    double tolerance = ...;
    double expectedAnswer = ...;
    assertEquals("GoFigure didn't work!", expectedAnswer,
         actualAnswer, tolerance);

    int expectedNumPasses = ...;
    assertEquals("GoFigure had wrong number passes!",
        expectedNumPasses, calc.numPasses);

    double expectedIntermediate = ...;
    assertEquals("GoFigure had wrong intermediate values!",
        expectedIntermediate, calc.intermediate, tolerance);
  }
}

Notez les 2 dernières vérifications. Ils ont utilisé les données publiques dans le test double qui a été injecté dans la classe testée. Je ne pouvais pas faire cela avec du code de production à cause du principe de masquage des données. Je ne voulais pas qu'un code de test spécial soit inséré dans le code de production. Les données publiques devaient appartenir à une classe différente.

Le test double a été injecté. C'est différent d'une simple stratégie car il affecte les données et pas seulement les fonctions.


4

L'injection de dépendance est un raffinement du modèle de stratégie que je vais expliquer brièvement. Il est souvent nécessaire de choisir entre plusieurs modules alternatifs lors de l'exécution. Ces modules implémentent tous une interface commune afin qu'ils puissent être utilisés de manière interchangeable. Le but du modèle de stratégie est d'éliminer le fardeau de décider lequel des modules à utiliser (c'est-à-dire quelle «stratégie concrète» ou dépendance) en encapsulant le processus de prise de décision dans un objet séparé que j'appellerai l'objet de stratégie.

L'injection de dépendances affine le modèle de stratégie non seulement en décidant quelle stratégie concrète utiliser, mais en créant une instance de la stratégie concrète et en la «réinjectant» dans le module appelant. Ceci est utile même s'il n'y a qu'une seule dépendance car la connaissance de la façon de gérer (initialiser, etc.) l'instance de stratégie concrète peut également être cachée dans l'objet de stratégie.


1

En fait, l'injection de dépendances ressemble également beaucoup au modèle Bridge. Pour moi (et selon la définition), le modèle Bridge est de s'adapter à différentes versions de l'implémentation, tandis que le modèle Strategy est pour la logique totalement différente. Mais l'exemple de code semble utiliser DI. Alors peut-être que DI n'est qu'une technique ou une implémentation?


0

La stratégie est une arène pour utiliser vos compétences d'injection de dépendance. Les vraies façons d'implémenter l'injection de dépendances sont les suivantes: -

  1. Événements
  2. Fichiers de configuration de la carte unité / structure (ou par programmation) etc.
  3. Méthodes d'extension
  4. Modèle d'usine abstraite
  5. Inversion du modèle de contrôle (utilisé à la fois par la stratégie et l'usine abstraite)

Il y a cependant une chose qui fait que la stratégie se distingue. Comme vous le savez dans Unity, lorsque l'application démarre, toutes les dépendances sont définies et nous ne pouvons pas les modifier davantage. Mais la stratégie prend en charge le changement de dépendance d'exécution. Mais NOUS devons gérer / injecter la dépendance, pas la responsabilité de la stratégie!

En fait, la stratégie ne parle pas d'injection de dépendance. Si nécessaire, cela peut être fait via Abstract Factory dans un modèle de stratégie. La stratégie ne parle que de créer une famille de classes avec interface et de «jouer» avec elle. En jouant, si nous trouvons que les classes sont dans un niveau différent, nous devons l'injecter nous-mêmes mais pas le travail de stratégie.


0

Si nous considérons les principes SOLID - Nous utilisons un modèle de stratégie pour le principe ouvert fermé et l'injection de dépendance pour le principe d'inversion de dépendance


1
Je ne suis pas sûr de suivre, pourriez-vous nous expliquer comment la stratégie est liée au principe ouvert / fermé et comment DI est liée au DIP?
Adam Parkin
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.