3

I was reading "Beginning Spring" and this particular paragraph caught my attention:

The DI pattern resembles other patterns such as Factory or Strategy. We can say that with the Factory pattern the instantiation of objects is still within the responsibility of the Factory definition, which is your code, but with the DI it’s externalized to another component/framework. On the other hand, with the Strategy pattern, the current implementation gets replaced with the help of multiple objects of a same interface, which contain that implementation inside. However, with the DI, the objects that contain those implementations are wired regardless of the implementation defined.

I am not sure if I understand what the author is saying in the emphasised part, but reading this made me realise, Strategy Pattern is an Inversion of Control implementation, isn 't it? (Q1)

So my second question (Q2) is: How is Strategy Pattern different compared to Dependency Injection?

  • 5
    Keep in mind that IoC exists on a different level than design patterns like Strategy, Factory, or whatever it may be. You can pretty much have DI combined with almost any pattern, or not use it at all and still use pretty much any pattern. They are completely orthogonal. – T. Sar Sep 8 '17 at 17:36
  • 1
    Can you provide a bit more text from that book? The disembodied quote you provided really doesn't make much sense without more context. – Robert Harvey Sep 8 '17 at 17:48
  • 2
    Your second question has already been adequately answered elsewhere. – Robert Harvey Sep 8 '17 at 17:56
3

The strategy pattern, simply put, is providing the ability to specify a concrete behavior for something so that its consumer can ignore what the concrete behavior is. An example is something like a logging strategy. The thing doing the logging doesn't care where the log messages go.

Dependency Injection is the idea that things are given their dependencies rather than seeking them out.

There's still scenarios where code would know how to build the strategy they want, or otherwise directly depend on the strategy implementations. They're uncommon and best avoided, but hopefully that helps distinguish the orthogonal concepts for you.

| improve this answer | |
  • But often with the strategy pattern, a class is given a strategy via some method or other so they are more similar than you are letting on. – Andrew S Mar 27 at 4:05
  • @AndrewS - not in my experience. – Telastyn Mar 27 at 13:27
  • Then maybe its fair to say they are semantically similar but contextually different. – Andrew S Mar 28 at 12:56
  • @AndrewS - no. They are semantically very different. That they happen to be used in combination, is... well pretty much everything is used in combination with dependency injection. I’m not sure why a 3 year old answer merits such attention. – Telastyn Mar 28 at 14:57
  • Ok, expand your answer and demonstrate this clearly and with class diagrams without deviating from what would be considered a standard implementation of these patterns. I'm not doubting you I just think this would be important to show/prove. – Andrew S Mar 28 at 15:02
2

From my PoV, the most useful way to look at the difference is:

Dependency Injection: Multiple ways to do conceptually the same thing (e.g. "storing an object" in Db A, Db B or FakeDb)

Strategy: Parameterize the function to have conceptually different functionality (e.g. SortAsc, SortDesc or SortByLastName)

| improve this answer | |
1

with the Strategy pattern, the current implementation gets replaced with the help of multiple objects of a same interface,

Is trying to say that if A knows how to use B because A knows the I interface that B implements then A can swap out B for C so long as C also implements I.

A--(I)-->B can be easily changed to A--(I)-->C

The strategy pattern is about being able to change from one to the other at run time.

However, with the DI, the objects that contain those implementations are wired regardless of the implementation defined.

Dependency Injection is about doing A--(I)-->B now expecting that eventually someone will need a feature that will make you create C.

| improve this answer | |
0

Late to the party, but I wanted to give a 'refactoring' example to complement other peoples' answers.

I'm going to use the example of a class that decompresses a file:

public class FileDecompressor
{
   public void DecompressFile()
   {
      string filePath = "/path/to/file/file.gzip";
      if (filePath.EndsWith(".gzip"))
      {
         unzipGZipFile(filePath);
      }
   }
}

Dependency Injection (DI) is providing a dependency to an object, but doesn't require the dependency to be any particular shape. You might pass the dependency into the object as a constructor argument, attach it to a field or property, or pull it from a container object. In our example the decompress file method creates the filepath that it is dependent on, "/path/to/file/file.gzip". To let that dependency (the filepath) be set by the method consumer, we can make the dependency a method parameter, like so:

   public void DecompressFile(string filePath)
   {
      if (filePath.EndsWith(".gzip"))
      {
         unzipGZipFile(filePath);
      }
   }
...

...

So, that's DI - Moving the provision of dependencies to the consumer of a method or class.

The strategy pattern is a specific implementation of a generic behavior. In our example, we've hardcoded that we decompress .gzip files only. If we want to change just that portion of if, we could let the consumer insert a "DecompressionStrategy" that would dictate how to decompress the file.

Our final code could look something like this:

public class FileDecompressor
{
   IDecompressionStrategy DecompressionStrategy;

   public FileDecompressor(IDecompressionStrategy decompressionStrategy)
   {
      // This is the strategy object being DIed into the class.
      DecompressionStrategy = decompressionStrategy;      
   }

   public void DecompressFile(string filePath)
   {
      DecompressionStrategy.DecompressFile(filePath);
   }
}

Now you could use all of these as a consumer:

// Seeing both DI and strategy pattern in use
var gzipDecompressor = new FileDecompressor(GZipDecompressionStrategy); 
var 7zDecompressor = new FileDecompressor(7zDecompressionStrategy);
etc..

In this small example, it's harder to see the benefit, because the FileDecompressor class doesn't have any non-pass-through logic, but if you extend the FileDecompressor class to do something like take a path and filename, or add additional error-handling logic, it becomes easier to see the benefits of using the strategy pattern.

| improve this answer | |

Not the answer you're looking for? Browse other questions tagged or ask your own question.