4
votes

We're using Ninject for IOC.

All of our Repository objects can (and should be) mocked for unit testing. I'd like to enforce that all developers code only to interfaces when interacting with Repositories. For this, I'd like to make the constructors private and create static accessor factory methods for construction:

public class SomeRepository : ISomeRepository
{
 private SomeRepository()
 {
 }
 public static ISomeRepository Create()
 {
   return StandardKernel.Get<ISomeRepository>();
 }
}

Problem lies in this: how do I have Ninject create the actual object? I have repository interface and class in the same project

3
Obligatory Service Locator link. I would read this twice before proceeding with your design - StandardKernel.Get looks like a Service Locator from here. I won't say "Service Locator is definitely wrong here", but Mark Seemann would, and I would trust him over me if I were you.default.kramer
Why do you want to enforce private constructors? No offense but I think you should trust your developers and simply define certain written or spoken convetions instead of overcomplicating things with an awkward design...Daniel Marbach
@default.kramer: completely agree with the article, which is why I want to not fall into the same trap. By having no other way of creating objects, I am planning to force maintenance developers to use IOC instead of direction instantiationIgorek
@DanielMarbach: we have a number of maintenance developers and even some feature developers who simply will take the shortest route to solving the problem, and "new someobject()" is the shortest route, instead of setting up a mapping between an interface and an object and later on using some weird syntax to instantiate. It's the reality :(Igorek
I deleted my answer again as I wasn't happy with it. I went over some documentation regarding IoC, DI and Ninject and came to the conclusion to agree with Daniel Marbach regarding code reviews. the Ninject StandardKernel uses the rules provided during construction to determine the concrete instance and return a completed object to the calling method. Why let SomeRepository use the kernel? Isn't the idea of IoC for SomeRepository not to have to constrcut or load it's own dependencies? I agree code reviews is the way to go to ensure all developers use the kernel as required.Nope

3 Answers

3
votes

We're ultimately going with the following:

public class SomeRepository : ISomeRepository
{
 private SomeRepository()
 {
 }
 public static ISomeRepository CreateForIOC()
 {
   return new SomeRepository();
 }
}

and during module loading, we're mapping the StandardKernel's ISomeRepository interface to CreateForIOC() method.

This does not stop developers from calling CreateForIOC directly, but at least forces them to a) code to an interface, b) realize that CreateForIOC() is probably not the right method to call when instantiating the object and at least ask a question about it from a lead developer

1
votes

Instead of either the private constructor or the factory method, why not just have Ninject provide the the concrete repository to any objects that need it?

0
votes

It looks like you're trying to use a singleton pattern. In general, the singleton pattern is considered an anti-pattern, largely because it hinders unit testing. Dependency injection allows you to create singletons via configuration without having to use the singleton pattern.

I would suggest that you instead, simply configure Ninject to create a single instance of your app without the private constructor.