What is the difference between Strategy pattern and Dependency Injection?

25,536

Solution 1

DI and Strategy work in the same way, but Strategy is used for more fine-grained and short-lived dependencies.

When an object is configured with a "fixed" Strategy, for example when the object is constructed, the distinction between Strategy and DI blurs. But in a DI scenario it is more unusual that the dependencies of objects change during their lifetimes, while this is not uncommon with Strategy.

Also, you can pass strategies as arguments to methods, while the related concept of method argument injection is not widespread and mostly used in the context of automated testing only.

Strategy focuses on intent and encourages you to create an interface with different implementations that obey the same behavioral contract. DI is more about just having an implementation of some behavior and providing it.

With DI you can decompose your program for other reasons than just to be able to swap parts of the implementation. An interface used in DI with only one implementation is very common. A "Strategy" with only one concrete implementation (ever) is not a real problem but is probably closer to DI.

Solution 2

The difference is what they are trying to achieve. The Strategy pattern is used in situations where you know that you want to swap out implementations. As an example, you might want to format data in different ways - you could use the strategy pattern to swap out an XML formatter or CSV formatter, etc.

Dependency Injection is different in that the user is not trying to change the runtime behaviour. Following the example above, we might be creating an XML export program that uses an XML formatter. Rather than structuring the code like this:

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

you would 'inject' the formatter in the constructor:

public class DataExporter {
  IFormatter formatter = null;

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

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

There are a few justifications for Dependency Injection, but the primary one is for testing. You might have a case where you have a persistence engine of some sort (such as a database). However, it can be a pain to use a real database when you're running tests repeatedly. So, for your test cases, you would inject a dummy database, so that you don't incur that overhead.

Using this example, you can see the difference: we always plan on using a data storage strategy, and it's the one that we pass in (the real DB instance). However, in development and testing, we want to use different dependencies, so we inject different concretions.

Solution 3

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.

Solution 4

Dude, dependency injection is a more general pattern, and it's about dependency on abstractions not concretions and it's a part of every pattern, but Strategy pattern is a solution to more specific problem

this is the definition from wikipedia:

DI:

Dependency injection (DI) in object-oriented computer programming is a design pattern with a core principle of separating behavior from dependency resolution. In other words: a technique for decoupling highly dependent software components.

Strategy Pattern:

In computer programming, the strategy pattern (also known as the policy pattern) is a particular software design pattern, whereby algorithms can be selected at runtime.

The strategy pattern is intended to provide a means to define a family of algorithms, encapsulate each one as an object, and make them interchangeable. The strategy pattern lets the algorithms vary independently from clients that use them.

Solution 5

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.

Share:
25,536

Related videos on Youtube

Nero
Author by

Nero

Updated on May 17, 2020

Comments

  • Nero
    Nero almost 4 years

    Strategy pattern and Dependency Injection both allow us to set / inject objects at run time. What is the difference between Strategy pattern and Dependency Injection?

  • Robert Gould
    Robert Gould almost 15 years
    I think I understand your gist, but I can't place it in words correctly... So your saying DI is more of a implementation pattern while strategy is more of a design pattern, and one way to implement strategy is through DI?
  • James Black
    James Black almost 15 years
    That sounds like a good way to put it. DI is more than just a strategy pattern. I found the same confusion with AOP, where people think it is a factory pattern. I think DI can implement the strategy pattern, so your rewording would appear to be fantastic. :)
  • Kalpesh Soni
    Kalpesh Soni over 10 years
    An interface used in DI with only one implementation is very common - so then what is DI in this particular case?
  • Sergey Telshevsky
    Sergey Telshevsky almost 10 years
    This quote basically explains it all: in a DI scenario it is more unusual that the dependencies of objects change during their lifetimes, while this is not uncommon with Strategy
  • GFranke
    GFranke about 7 years
    Strategy: Classes are designed so that they can be configured with an algorithm at run-time. DI: Such classes get an algorithm (a Strategy object) injected at run-time. From the GoF Design Patterns Memory at w3sdesign.com.
  • Adam Parkin
    Adam Parkin over 5 years
    I'm not sure I follow, could you elaborate on how Strategy relates to the Open/Closed principle and how DI relates to the DIP?

Related