javaarchitectureinversion-of-controlioc-containertestability

whats wrong with a simple IOC container class?


last day I implemented a simple class to serve as IOC container (not much like that) in one of my playground projects and some pro guy told me that is going to have some problem when testing the code (too vein to share what exactly is the problem !!)

although I always use IOC frameworks myself, I wanted to know why exactly this methodology is bad ?

I even wrote many tests (using mock frameworks) using this methodology and never had a problem.

I want your Idea about design problems of this:

public class IocContainer{

  private static IocContainer instance;

  private IocContainer(){
  }

  public static IocContainer getInstance()
  {
    if(instance == null){
      instance = new IocContainer();
    }
    return instance;
  }

  public ChatPresenter getChatPresenter(ChatView chatView)
  {
    return new ChatPresenterImpl(chatView, getChatRepo() , getMessagingService());
  }

  private ChatRepo getChatRepo()
  {
    return new ChatRepoImpl(getDbHelper(), getRemoteService());
  }

  private MessagingService getMessagingService()
  {
    return new MessagingServiceImpl()
  }

  private DbHelper getDbHelper()
  {
    return new DbHelperImpl();
  }

  private RemoteService getRemoteService()
  {
    return new RemoteServiceImpl();
  }
}

as you see I only made getChatPresenter accessible and I use this like below in my view and it works well.

ChatPresenter presenter = IocContainer.getInstance().getChatPresenter(this)

the code handles inversion of control without any tight coupling (using interfaces).

I wanna know any wrong thing with this approach ? (I want answers from technical point of view cuz I already know using a Ioc container library is easier has more features like scopes and so ...)

Actually I want to know any problem and limitation this approach would make in the future ?

be cruel and kill me :D


Solution

  • To summarize the comment trail:

    Your approach looks like the service locator as described here by Martin Fowler: http://martinfowler.com/articles/injection.html#InversionOfControl

    There's a major difference between what Martin describes and your code: your code directly creates instances of your services and thus is more of a factory than a registry.

    The basic idea/goal of inversion-of-control is to reduce coupling by reducing dependencies, which doesn't happen if your container depends on the service implementations (which it needs to directly call the constructors). So the implementation in your question somewhat opposes that basic idea.

    One of the disadvantages of depending on the implementations would be that the services can't be replaced without having to recompile the container. That might not be a problem if you'll most likely never have different implementations anyway but if you might need it, a service registry would be more useful.

    A registry normally provides for methods to register implementations of services and deliver one upon request. Which is delivered depends on your needs but it could be as simple as the first implementation found or be more complex, e.g. by matching some parameters (for some idea on that have a look at CDI injection point parameters and alternatives).

    The registry is generally accompanied by some means to configure the registry, e.g. via config files or classpath scanning (automatic lookup on plugins that are present). However, it might also be sufficient to just write some code that configures the registry. It all depends on what coupling you need to get rid of (to solve a problem you face) and which coupling is acceptable.