niks
niks

Reputation: 659

Which dependency injection "factory" to use?

I have two options for creating a ViewModel factory to inject into other classes:

OPTION A

public interface IFactory
{
    ViewModelA CreateViewModelA(string data);
    ViewModelB CreateViewModelB(string data);
}

public class MyFactory : IFactory
{
    public MyFactory(){}

    public ViewModelA CreateViewModelA(string data)
    {
        return new ViewModelA (data);
    }

    public ViewModelA CreateViewModelB(string data)
    {
        return new ViewModelB (data);
    }
}
//register factory
container.RegisterType<IFactory, MyFactory>(new ContainerControlledLifetimeManager());

OPTION B

public interface IFactory
{
    T CreateViewModel<T>();
}
public class MyFactory : IFactory
{
    public MyFactory(IUnityContainer unityContainer)
    {
        _container = unityContainer;
    }
    private IUnityContainer _container { get; set; }

    public T CreateViewModel<T>()
    {
        return (T)this._container.Resolve<T>();
    }
}
//register factory
var container = new UnityContainer();
container.RegisterType<IFactory, MyFactory>(new ContainerControlledLifetimeManager(), new InjectionConstructor(container));
//inject this where neccessary

OPTION B seems easier to implement, however I am not sure if using the container in such a way is correct. I have read about service locator anti-pattern and in this situation the way I have passed container into constructor of another class seems to resemble this problem. So which option should I go for and if possible to elaborate, why?

Upvotes: 1

Views: 55

Answers (1)

Mark Seemann
Mark Seemann

Reputation: 233125

Favour option A for a number of reasons:

First, in option B, MyFactory doesn't really do anything. Even the generic cast in return (T)this._container.Resolve<T>(); is redundant, so it's nothing but an Adapter over IUnityContainer. In all the code where you'd depend on the B version of IFactory, you could just as well depend directly on IUnityContainer (ignoring the Interface Segregation Principle for now).

Second, though, IUnityContainer (and thereby also option B) is a Service Locator, which is an anti-pattern. One problem is that it offers an infinity of methods that you can call at compile time, but which will fail at run time. It also violates encapsulation.

Option A, on the other hand, isn't a Service Locator. It only offers a finite API. I'd probably go with a generic interface instead, though:

public interface IFactory<T>
{
    T Create(object context);
}

You have various options for how you want to implement the interface, but keep in mind that software development productivity doesn't have much to do with how long it takes to type something in. The decision shouldn't be made on which alternative is easiest to implement, but rather on which version results in code that is easiest to understand.

You spend much more time reading code than writing it.

Upvotes: 1

Related Questions