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.