2

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!

Community
  • 1
  • 1
luddet
  • 1,235
  • 1
  • 11
  • 11
  • +1 for well structured and written question... – Dean Kuga Apr 25 '12 at 16:30
  • Maybe I'm missing the point or the example has been over-simplified, but why would you need a factory if you don't need to decide at run-time what to instantiate? You could just inject ITranscoder. – Filippo Pensalfini Apr 26 '12 at 08:08
  • @filpen The engine needs to instantiate a new ITranscoder for each item. If there is a way to do that without a factory, that could very well be a solution in this particular case. – luddet Apr 26 '12 at 11:47
  • @luddet Ok, that pretty much clears it. I edited my answer, I hope that puts you on the right track. – Filippo Pensalfini Apr 26 '12 at 12:03

3 Answers3

1

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.

1

If you really need a factory (see comment), then this blog post by Mark Seemann addresses this issue.

Briefly, if you use the IoC Container in your factory, you want to use it in the composition root. If not, there is no harm for it to remain in the same assembly as the class it is instantiating.

EDIT

For your particular case, you do not need a factory, since you already have everything you need to solve this dependency.

using SimpleFFmpeg;
namespace PusherLib {
    public class PusherEngine {
        private readonly ITranscoder _transcoder;
        private readonly List<VideoItem> _items;

        public PusherEngine(ITranscoder transcoder) {
            _items = new List<VideoItem>();
            _transcoder = transcoder;
        }

        // ...

        public void processItems() {
            foreach (VideoItem item in _items) {
                _transcoder.Transcode(item.FileName);
            }
        }

        // ...
    }
}

The initialization would then look like this:

namespace Pusher {
    class Program {
        static void Main(string[] args) {
            ITranscoder t = new Transcoder();
            PusherEngine pe = new PusherEngine(t);
            pe.addVideoItem(new VideoItem(...));
            pe.processItems();
        }
    }
}

The reason why a factory was needed in the answer you linked is that the dependency needed values only known at run-time to be able to be instantiated, while your dependency does not require run-time dependent arguments to be created.

Filippo Pensalfini
  • 1,714
  • 12
  • 16
  • I will need to create new instances of the transcoder, since I plan to make the processing multithreaded. (A whole new set of headaches :) ) So I do believe a factory is the way to go. And regardless, it's the principle was looking for. The link you provided to Mark Seemanns blog helped alot! Thanks! – luddet Apr 26 '12 at 13:16
  • I don't have enough "reputation" to mark your answer as useful, otherwise I would have. – luddet Apr 26 '12 at 13:24
0

To answer your actual question, and not if this is a good use case for a factory or not:

For this purpose I sometimes split up Interface and Implementation into different projects, and something like your IFactory<> would live in the Common.I project. This doesn't work in every scenario, but one of the advantages of this approach for me is that I can swap out Implementation dll's with either mocks or a new implementation when there are underlying technology changes.
For example, we recently switched from parsing xml files from a directory to getting data from a service. The only thing I had to update on client machines was this one Implementation dll because the interface did not change at all.

But I guess in the end it doesn't really matter, as mentioned before.

RoelF
  • 7,483
  • 5
  • 44
  • 67