Ces termes sont-ils égaux ou existe-t-il des différences importantes entre l'injection de dépendances et le modèle de stratégie ? Pour moi, il semble que Martin Fowler ait simplement renommé le modèle de stratégie avec un nom plus accrocheur, est-ce que je rate quelque chose ?
Réponses
Trop de publicités?Vous pouvez utiliser DI comme un modèle de stratégie, de sorte que vous pouvez échanger l'algorithme qui est nécessaire pour chaque client, mais DI peut aller au-delà de cela comme il est un moyen de découpler les parties d'une application, qui ne ferait pas partie du modèle de stratégie.
Il serait risqué de dire que DI n'est qu'un modèle de stratégie renommé car cela commence à diluer ce à quoi le modèle de stratégie sert vraiment, IMO.
Les stratégies sont des éléments de plus haut niveau qui sont utilisés pour modifier la façon dont les choses sont calculées. Avec l'injection de dépendances, vous pouvez modifier non seulement la façon dont les choses sont calculées, mais aussi ce qui s'y trouve.
Pour moi, cela devient clair quand on utilise des tests unitaires. Pour l'exécution du code de production, toutes les données sont cachées (c'est-à-dire privées ou protégées), alors qu'avec les tests unitaires, la plupart des données sont publiques et je peux les examiner avec les assertions.
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 (...);
}
}
Remarquez 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épendance :
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 (...);
}
}
Utilisez :
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);
}
}
Remarquez les 2 derniers contrôles. Ils ont utilisé les données publiques dans le double de test qui a été injecté dans la classe testée. Je ne pouvais pas faire ça avec du code de production à cause du principe de données. Je ne voulais pas que du code de test à usage spécifique soit inséré dans le code de production. Les données publiques devaient se trouver dans une classe différente.
Le double test a été injecté. C'est différent d'une simple stratégie puisque cela a affecté données et pas seulement des fonctions.
L'injection de dépendances est un raffinement du modèle de stratégie que je vais brièvement expliquer. Il est souvent nécessaire de choisir entre plusieurs modules alternatifs au moment 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 patron de stratégie est de supprimer la charge de décider lequel des modules utiliser (c'est-à-dire quelle "stratégie concrète" ou dépendance) en encapsulant le processus 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 en ne se contentant pas de décider de la stratégie concrète à utiliser, mais en créant une instance de la stratégie concrète et en l'"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 la stratégie concrète peut également être cachée dans l'objet de stratégie.
En fait, l'injection de dépendances ressemble aussi beaucoup au modèle Bridge. Pour moi (et d'après la définition), le modèle Bridge est destiné à s'adapter aux différents types d'utilisateurs. versions de l'implémentation, alors que le modèle Strategy est destiné à une logique totalement différente. Mais l'exemple de code semble utiliser DI. Alors peut-être que DI est juste une technique ou une implémentation ?
La stratégie est une arène pour utiliser vos compétences en matière d'injection de dépendances. Les moyens réels de mettre en œuvre l'injection de dépendances sont les suivants:-
- Événements
- Fichiers de configuration de unity/structure map(ou programmatiquement) etc.
- Méthodes d'extension
- Modèle de fabrique abstraite
- Le modèle d'inversion de contrôle (utilisé à la fois par la stratégie et la fabrique 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 plus les modifier. Mais la stratégie prend en charge le changement des dépendances en cours d'exécution. Mais NOUS devons gérer/injecter la dépendance, ce qui n'est pas du ressort de Strategy !
En fait, la stratégie ne parle pas d'injection de dépendances. Si nécessaire, cela peut être fait par le biais d'une fabrique abstraite dans un modèle de stratégie. La stratégie ne parle que de la création d'une famille de classes avec interface et de "jouer" avec elle. En jouant, si nous constatons que les classes se trouvent dans un niveau différent, nous devons les injecter nous-mêmes, mais ce n'est pas le rôle de Strategy.