0

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

Amir Ziarati
  • 14,248
  • 11
  • 47
  • 52
  • 1
    `private static instance;` - that can't even compile ... – Thomas Jun 05 '18 at 08:23
  • thanks . it was more of typo cuz I wrote the code with no IDE. – Amir Ziarati Jun 05 '18 at 08:28
  • From a conceptual point of view I'd say this isn't really IoC since your `ChatView` class still is in control of aquiring a chat presenter - your code looks more like the factory pattern. – Thomas Jun 05 '18 at 08:29
  • its the IocContainer class who mathes the interfaces with concretes. how do you say this ? please explain more ? – Amir Ziarati Jun 05 '18 at 08:32
  • since I know the main responsibility of an Ioc container is to provide a concrete for an interface. am I wrong ? – Amir Ziarati Jun 05 '18 at 08:34
  • 1
    Have a look here: https://martinfowler.com/articles/injection.html#InversionOfControl . Your code basically looks like the service locator approach but your container isn't a registry that someone else fills but a factory that creates the instances itself. – Thomas Jun 05 '18 at 09:50
  • that was hell of an awesome article. thanks for that. this article was never against Service Locator and it even suggests that its more simple. but as you told mine is not even a service locator because in service locator you dont instantiate concrete explicitly but you make a registry (without the disadvantage of blur dependency chain and all my code use constructor dependencies). so now technically is that gonna be a problem ? what would its limitation be ? – Amir Ziarati Jun 05 '18 at 11:56
  • 1
    Well, the limitations would be that `IocContainer` always depends on the concrete implementation(s) of the interfaces and thus it's coupled to those. With a service registry you'd invert that, e.g. so that your service implementations register themselves or some loading mechanism does that. That would allow you to add or replace services without having to recompile `IocContainer`. - In essence IoC is meant to reduce coupling, that's why you'd bother to add that complexity to your application. – Thomas Jun 05 '18 at 14:01
  • you mean I can add a hashmap and load it some where in a config phase ? ok now what if one of the dependencies is not available at config time ? like the presenter which wants the view as a dependency and thats not available until user navigates to that view ? – Amir Ziarati Jun 05 '18 at 14:11
  • 1
    It might be multiple maps or even sets like `Set presenters` etc. (and you select one based on whatever you need, could be just the first one). Also you'd need to make sure that the dependencies are resolved when they are needed (or before), i.e. when a view requests a presenter it should already be present - the presenter would need to be resolved at that time at the latest. Generally, at config time you'd either assume the dependencies _will_ be present, allow for them to be missing or check whether they're available and abort if not (you'd normally do that at startup). – Thomas Jun 05 '18 at 14:22
  • I think I got the Idea. what I am having problem with is some of my resolvings are dependent to the state of the program. there is a concept called Module in some IOC containers. this modulize the dependency container. then whenever some view opens you config and start that specific view module sending the view as a parameter to config method. this way all dependency chain of that module will be present at the time of config (which some of them are out of your control to be present) – Amir Ziarati Jun 05 '18 at 17:44
  • in my case (Android), views are created by the framework so I cant instantiate a view. when a view is created by android (through user request) it comes to the scope of my code for the view. then I need to resolve a presenter and the view is needed in time of IOC config. so now I understand why Dagger Ioc Library has modules. that was an awesome discussion thank you very much for your help. – Amir Ziarati Jun 05 '18 at 17:47
  • actually the best part of your comments was the part you talked about how my class is dependent to the concretes and I cant add or replace services without having to recompile my code. just add it as an answer and I will accept it. I see how concerns are different at back-end and client. I as a android developer never think about changing something without recompiling because we never need to worry about it. and not having this may stop us from thinking clearly about the right code design. – Amir Ziarati Jun 05 '18 at 17:55
  • 1
    Will do that :) Besides that, there are different views of what good code design is. The Java world tends to provide for cases that never happen (like providing for plugin mechanisms that aren't used) so if you figure you won't ever need that then a simpler design might still be ok. – Thomas Jun 05 '18 at 20:14
  • yea right. I think the most important thing that even Fawler has stated in his article is seperating config from implementation is more important than using a service locator or IOC container. actually mine is none :D but if I seperate config it can get like an IOC container a little. – Amir Ziarati Jun 05 '18 at 20:19

1 Answers1

1

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.

Thomas
  • 87,414
  • 12
  • 119
  • 157
  • 1
    this is also a great article about common mistakes in using IOC containers: https://www.devtrends.co.uk/blog/how-not-to-do-dependency-injection-the-static-or-singleton-container – Amir Ziarati Jun 06 '18 at 05:48
  • 1
    @AmirZiarati thanks for the link. When it comes to dependency injection I'd recommend you have a look at frameworks like CDI (part of JavaEE), Guice etc. - I used CDI to some good success when it comes to decoupling (e.g. implementations register themselves to a registry when they are loaded by the JVM). – Thomas Jun 06 '18 at 07:46