Are these terms equal or are there any important differences between dependency injection and the strategy pattern? Too me it seems like Martin Fowler just renamed the strategy pattern with a catchier name, am I missing something?
You can use DI as a strategy pattern, so you can swap in the algorithm that is needed for each customer, but, DI can go beyond that as it is a way to just decouple the parts of an application, which wouldn't be part of the strategy pattern.
It would be risky to say that DI is just a renamed strategy pattern as that starts to dilute what the strategy pattern really is for, IMO.
Strategies are higher-level things that are used to change how things are computed. With dependency injection, you can change not just how things are computed but also change what is there.
For me, it becomes clear when using unit tests. For production code execution, you have all the data hidden (i.e. private or protected); whereas, with unit tests, most of the data is public so I can look at it with the Asserts.
Example of strategy:
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 (...);
}
}
Notice that there is no public data that is different between the strategies. Nor is there any different methods. Both strategies share all the same functions and signatures.
Now for the dependency injection:
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 (...);
}
}
Use:
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);
}
}
Notice the last 2 checks. They used the public data in the test double that was injected into the class under test. I couldn't do this with production code because of the data hiding principle. I didn't want to have special purpose testing code inserted in the production code. The public data had to be in a different class.
The test double was injected. That is different than just a strategy since it affected data and not just functions.