10

I'm using Unity as IoC with C#, but I guess the question really isn't really limited to Unity and C#, but IoC in general.

I try to follow the SOLID-principle, which means that I got very few dependencies between two concrete classes. But when I need to create new instances of a model, what's the best way to do it?

I usually use a factory create my instances, but there's a few alternatives and I wonder which is better, and why?

Simple Factory:

public class FooFactory : IFooFactory
{
    public IFoo CreateModel()
    {
        return new Foo(); // references a concrete class.
    }
}

Service-locator-factory

public class FooFactory : IFooFactory
{
    private readonly IUnityContainer _container;

    public FooFactory (IUnityContainer container)
    {
        _container = container;
    }

    public IFoo CreateModel()
    {
        return _container.Resolve<IFoo>(); // Service-locator anti-pattern?
    }
}

Func-factory. No dependencies to other classes.

public class FooFactory : IFooFactory
{
    private readonly Func<IFoo> _createFunc;

    public FooFactory (Func<IFoo> createFunc)
    {
        _createFunc= createFunc;
    }

    public IFoo CreateModel()
    {
        return _createFunc(); // Is this really better than service-locator?
    }
}

Which IFooFactory should I use, and why? Is there a better option?

The examples above are of a more conceptual level, where I try to find a balance between SOLID, maintainable code and service locator. Here's an actual example:

public class ActionScopeFactory : IActionScopeFactory
{
    private readonly Func<Action, IActionScope> _createFunc;

    public ActionScopeFactory(Func<Action, IActionScope> createFunc)
    {
        _createFunc = createFunc;
    }

    public IActionScope CreateScope(Action action)
    {
        return _createFunc(action);
    }
}

public class ActionScope : IActionScope, IDisposable
{
    private readonly Action _action;

    public ActionScope(Action action)
    {
        _action = action;
    }

    public void Dispose()
    {
        _action();
    }
}

public class SomeManager
{
    public void DoStuff()
    {
        using(_actionFactory.CreateScope(() => AllDone())
        {
           // Do stuff. And when done call AllDone().
           // Another way of actually writing try/finally.
        }
    }
}

Why do I use a Factory at all? Because I sometimes need to create new models. There are various scenarios when this is necessary. For eg. in a mapper and when the mapper has a longer lifetime than the object it should map. Example for factory usage:

public class FooManager
{
    private IService _service;
    private IFooFactory _factory;

    public FooManager(IService service, IFooFactory factory)  
    {
        _service = service;
        _factory = factory;
    }

    public void MarkTimestamp()
    {
        IFoo foo = _factory.CreateModel();
        foo.Time = DateTime.Now;
        foo.User = // current user
        _service.DoStuff(foo);
    }

    public void DoStuffInScope()
    {
        using(var foo = _factoru.CreateModel())
        {
            // do stuff with foo...
        }
    }
}
9
  • 3
    Why do you "usually use a factory"? In most cases you can simply inject an instance instead of a factory. And even if you need a factory, Func<IFoo> is already a factory, no need to wrap it in another class+interface. Apr 29, 2016 at 13:42
  • 1
    @CodesInChaos good question. It's really just a way for me to abstract the creation of models in order to be able to create really testable code with 100% code-coverage. I find it easier to mock the objects if I abstract the creation of them.
    – smoksnes
    Apr 29, 2016 at 13:44
  • Injecting an instance already removes the creation of the object from your class. I'd only inject a factory if the class needs to create multiple instances with different parameters. Apr 29, 2016 at 13:45
  • @CodesInChaos I've added some examples to when I use a factory.
    – smoksnes
    Apr 29, 2016 at 14:18
  • 1
    @RobertHarvey Good point. I added an actual factory that I use. But I really want to find a balance and know what's "good practice". But I guess it's really depends on the particular case...
    – smoksnes
    Apr 29, 2016 at 15:27

2 Answers 2

11

First things first, the mantra that service-locators are an anti-pattern is tiresome and counter productive. They have their downsides, but they're pretty much the same as conventional IoC containers except IoC containers are good.

That said, let's focus on your examples:

Simple factories are good. They are clear. They are easy to test. They are easy to extend.

Service locator factories are overkill for this scenario (and most scenarios, frankly). Service locators let you have a factory that can resolve from any arbitrary type to an instance of that type (or an exception). You don't need that here. You just need to be able to supply some IFoo.

The func-factory is weird here. You don't really need the interface, since Func<IFoo> is the interface (in the "a point where two things interact" definition). Sometimes you already have the interface and the func-factory isn't really a factory, but an adapter between the capital I interface and the func "interface".

Which is best will vary on your needs. Personally, I like just having a Func. It provides the most flexibility in use, while not having the boilerplate overhead of the simple factory.

And as much as I defend service locators as not being an anti-pattern, they do have a very limited use case, and your examples do not even come close to it.

2
  • 1
    Thank you for your feedback. I've added a more concrete example. Would you use the simple factory there as well?
    – smoksnes
    Apr 29, 2016 at 16:23
  • @smoksnes - I can't tell, since it's unclear what it's supposed to do. Naively, it seems overwrought.
    – Telastyn
    Apr 29, 2016 at 16:25
1

Factories are an exception to the:

  • no service locator
  • no singletons
  • no global variables
  • no tightly coupled dependencies

rules.

In theory, an enterprise code would be divided into two main parts:

  1. object graph constructors: place where classes are newed to become objects and are wired together based on either specific configuration, flags or general knowledge
  2. business layer: place containing pretty much everything that does not belong to group 1, this is where you write your business rules, where you (if you want to follow the clean code principles) follow IoC (DI for example) and where classes should have low coupling, high cohesion and concise interfaces

But even then, although having a service locator inside factories is not exactly a huge problem, there are situations where a manually written or automatically generated factory might prove to be a better solution than depending on a service locator (that is using a SI library will usually force you to transmit additional data with the SI library than you necessarily need).


Case 1

For dependencies, which have certain configuration that will either not change during the application process or when changed the changes have to reflect on the entire application, service locator is actually quite feasible idea.

Examples of some of these classes may be:

  • database,
  • caching
  • a source for web services.

These are usually global settings to your application, which, when changed, affect the object graph in a drastic way.

For example, if your config says you're currently using a MongoDB and you change the config to use MySQL instead, you are very likely to use MySQL for your entire application, not just for a certain part and you want your entire application to know to pull the data from MySQL now and ignore Mongo.


Case 2

When you need to construct an implementation of a general interface during a runtime based on either result from previously processed data or user input, you'll probably want to create your own factory with a switch/case providing a specific implementation based on the value that is passed to the factory method.

That way you're not transfering unnecessary code from the service locator, but have a very simple and lightweight factory.

An example of a case where this type of a factory would be used is when you want to pull data from two classes, which implement the same interface but on top of that have additional data and are constructed in completely different ways and different services must be provided to retrive them.

An example could be a foreach loop on a collection which would provide the flag for the decision, which implementation use. Inside this foreach, you'd pass value of the single iteration to the factory, which would construct a specific implementation but with the shared interface, which you can use to retrieve the common data for all the values in the collection you're running foreach on.

2
  • newed classes? But what about static constructors? ;) Aug 21, 2020 at 16:11
  • "place containing pretty much everything that does not belong to group 1" - in my opinion you should invert the logic - business logic is business logic and anything else particularly not pretty much everything that is not 1 because the way you propose we can lose SOLID and clean code very quickly. Additionally if there will be something more than business logic in 2. it will be very hard to change framework and business logic should be done the way that we can jump from one framework to another without moaning and craziness. Beside that I like your answer :) Aug 21, 2020 at 16:17

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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