Short question
Where should I put the abstract factory interface and the actual factory?
Overview
I’m writing a simple video transcoding application and I’m trying to wrap my head around dependency injection.
I have separated my application into several projects in visual studio.
- One class library for the transcoder, used by the application engine
- One class library for the application engine that will be used by a gui or console interface
- One console application that will be the main user interface for now
Without DI
This is what everything looks like before dependency injection
The transcoder lib:
namespace SimpleFFmpeg {
public interface ITranscoder {
void Transcode(String fileName);
}
public class Transcoder:ITranscoder {
// ...
public void Transcode(String fileName) {
// do transcoding stuff
}
// ...
}
}
The PusherEngine lib:
using SimpleFFmpeg;
namespace PusherLib {
public class PusherEngine {
private readonly List<VideoItem> _items;
public PusherEngine() {
_items = new List<VideoItem>();
}
// ...
public void processItems() {
foreach (VideoItem item in _items) {
ITranscoder t = new Transcoder();
t.Transcode(item.FileName);
}
}
// ...
}
}
The actual application:
namespace Pusher {
class Program {
static void Main(string[] args) {
PusherEngine pe = new PusherEngine();
pe.addVideoItem(new VideoItem(...));
pe.processItems();
}
}
}
Refactor to use DI
I create a generic abstract factory interface, like suggested in this question: Creating new instances while still using Dependency Injection
public interface IFactory<T> {
T Get();
}
Next I create a factory that creates ITranscoders
public class TranscoderFactory: IFactory<ITranscoder> {
public ITranscoder Get() {
return new SimpleFFmpeg.Transcoder();
}
}
Then I modify the PusherEngine to require a factory dependence in the constructor:
using SimpleFFmpeg;
namespace PusherLib {
public class PusherEngine {
private readonly IFactory<ITranscoder> _transcoderFactory;
private readonly List<VideoItem> _items;
public PusherEngine(IFactory<ITranscoder> transcoderFactory) {
_items = new List<VideoItem>();
_transcoderFactory = transcoderFactory;
}
// ...
public void processItems() {
foreach (VideoItem item in _items) {
ITranscoder t = _transcoderFactory.Get();
t.Transcode(item.FileName);
}
}
// ...
}
}
Finally, in the Program it looks like this:
namespace Pusher {
class Program {
static void Main(string[] args) {
IFactory<ITranscoder> f = new TranscoderFactory();
PusherEngine pe = new PusherEngine(f);
pe.addVideoItem(new VideoItem(...));
pe.processItems();
}
}
}
Question
In which lib/project should the IFactory interface be defined?
In which lib/project should the TranscoderFactory be defined?
Do they live in the Transcoder lib? In the PusherLib? Or in the actual frontend application?
I’m looking for best practices.
Thanks!
In my opinion, it doesn’t matter. For me, the main point of dependency injection is being able to inject something other than the real implementation while testing. I keep my unit tests in a separate project along with the various mock definitions used for testing. The real implementations as well as the ‘abstract’ logic are all kept in the same assembly/project/namespace.