-1

I have a list of IReader that I read at the beginning of my program. Later on I need ReaderFactory to get appropriate IReader based on Extensions it can use. The problem is the factory needs to know about available readers. So I have two options:

  1. Make static ReaderFactory with method static Get(string extension) and static Init(IEnumerable<IReader> readers) which would be called somewhere in my starting class.
  2. Make IReaderFactory with constructor and private IEnumerable<IReader> _readers and make an instance of this and pass it via Dependency Injection.

My question is which one would you use in this particular situation? Also maybe there is a third option that I don't know about?

  • 4
    Since your factory needs configuration/inputs, the first one is never appropriate. That Init method is horrible. – CodesInChaos Dec 29 '16 at 12:59
  • 1
    This doesn't sound like a factory pattern, but more like a dictionary lookup. – Erik Eidt Dec 29 '16 at 15:31
  • @ErikEidt: Wouldn't your dictionary just be an implementation detail? The same thing could be achieved with a case statement. – Robert Harvey Dec 29 '16 at 15:34
  • Probably I'm wrong, but should there be IEnumerable? or it should have been IEnumerator? – Candid Moon _Max_ Feb 28 '17 at 0:43
  • 1
    @JamesSnell Actually the project I was working on at that time used MEF extensively, and yes you are right. I could just export ReaderFactory and ImportMany readers. I think I have a couple of ways to solve this problem, and I think I'll post my own answer soon to close this question. I don't know why it was bumped to the homepage... – FCin Feb 28 '17 at 12:44
0

It might be pedantic at this point, but I do not believe that the Factory Pattern is appropriate for this situation.

If I were asked to write the code with a gun to my head, I would likely make a Provider.

ReaderProvider {
    private IEnumerable<IReader> _readers;

    public ReaderProvider(IEnumerable<IReader> readers) {
        _readers = readers;
    }

    public IReader GetReaderForExtension(string extension) {
        ...
    }
}

You could create this service when you read your list of readers, and inject the provider into the code that you require the reader.

If there is too much disconnect, you could use a singleton, but I generally tend to stay away from them when I can.

I hope that helps.

  • 2
    There is not really such a thing as "Factory Pattern". A factory is simply a class (or other unit) that returns instantiated objects. This is exactly what your example is doing. You are calling it a service, but it is a factory. In the original GoF book the "Factory Method" and "Abstract Factory" patterns are described, but neither is what the OP is asking about. – jhyot Dec 29 '16 at 22:45
  • Perhaps it is my opinion, but in my experience Factories tend to always be stateless. This is why I recommended creating a service, so that there was no unintentional confusion over the state or lack there of. – Blair Dec 30 '16 at 17:05
  • 1
    Because you not creating new instances, the name ofthe class can be ReaderProvider – Fabio Apr 29 '17 at 4:43
0

I would use #2 since it would be easier to stub out during unit testing. The static factory would require some sort of mocking and interception in order to isolate away.

0

Static anything are hard to unit test and also represent hidden dependencies, since they can be accessed from anywhere. Bad.

Instead, consider using your IoC container, but using "singleton" scope, e.g. with AutoFac you'd write this:

container.RegisterType<IReaderFactory, ReaderFactory>().SingleInstance();

The ReaderFactory can load the readers when it initializes itself. The initializer will be called only once and the same instance will be injected, with readers preloaded, into every class that depends on it.

If you do it this way you can still unit test, you haven't hidden any dependencies, and you maintain proper inversion of control with a single composition root.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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