0

I try to use as many interfaces as possible for a good unit test and a better understanding of the program architecture.

Despite the fact that I try to follow the SOLID rule - my classes need to pass a lot of dependencies in the constructor, which turns into hell.

The search led me to IoC containers, but in fact I didn’t understand much when to use them. Passing a NInject kernel in the constructor looks like a silly idea, and creating only the main class using the NInject does not eliminate the problem with a bunch of parameters in the constructor.

I can’t reduce the number of dependencies in constructor. I don’t understand how to properly use NInject to reduce constructor parameters. How do I solve this problem?

(not the worst example)

public SomeConstructor(ISettings settings, INotification notification, IServer server, IPriceCache priceCache)
{
    Settings = settings;
    Notification = notificartion;
    Server = server;
    PriceCache = priceCache;
}

(this solution looks like a terrible idea)

public SomeConstructor(IKernel ninjectKernel)
{
    Settings = ninjectKernel.Get<ISettings>();
    Notification = ninjectKernel.Get<INotification>();
    Server = ninjectKernel.Get<IServer>();
    PriceCache = ninjectKernel.Get<IPriceCache>();
}
Uwe Keim
  • 39,551
  • 56
  • 175
  • 291
Andrew
  • 129
  • 9
  • I am not sure that I understand, your constructor only has one parameter, that being the container. If you are referring to the number of dependencies that you have in the class itself, then that is another issue that has more to do with code coupling than what is being asked here – David Pilkington Jul 02 '19 at 04:32
  • @DavidPilkington Is it a good idea to create a central class that will store all interfaces and pass it to the constructor? – Andrew Jul 02 '19 at 04:54
  • Four constructor arguments is hardly *hell*. Even ten. More than that then I'd start to worry a little-- not about the DI approach, but about my object model, because it might indicate the class is doing too many things (see [Single Responsibility Principle](https://en.wikipedia.org/wiki/Single_responsibility_principle)). To answer your question, no, its not a good idea; [creating a central class is actually an anti-pattern](https://blog.ploeh.dk/2010/02/03/ServiceLocatorisanAnti-Pattern/). – John Wu Jul 02 '19 at 05:42
  • Related: [How to avoid dependency injection constructor maddness](https://stackoverflow.com/questions/2420193/how-to-avoid-dependency-injection-constructor-madness). – John Wu Jul 02 '19 at 05:46

2 Answers2

0

If you don't want anything in the constructor, then Ninject allows you to make use of something called Property Setter Injection with the use of attributes. It would look something like this:

class Samurai 
{    
    [Inject]
    public IWeapon Weapon { private get; set; }

    public void Attack(string target) 
    {
        this.Weapon.Hit(target);
    }
}

But as I mentioned in the comment above. All of this works out the essentially the same thing, just because you are not including the items in your constructor does not change the fact that you feel your code has a large number of dependencies.

David Pilkington
  • 13,528
  • 3
  • 41
  • 73
  • Can a good code require so many dependencies in a constructor? Or is this a likely sign that my code is bad? – Andrew Jul 02 '19 at 04:50
  • @Andrew you mentioned that you try to follow SOLID. Well the "S" is for Single Responsibility Principle. So I guess you need to ask yourself, is your class doing too much? It is perfectly possible that your class does need all this. Only you know the full context. – David Pilkington Jul 02 '19 at 05:00
0

One of the reasons to use IoC / DI is to get rid of lifetime scope responsibility - that is, component should request dependencies (via for example constructor injection, or property injection), but should not own them.

So, there should be some other class, usually called container of some sort, which manages lifetime scopes and dependencies.

In (ideal) well organized architecture, you never call resolve for services - you register all the services in the container, and let them live - then container will create components and resolve necessary dependecies for them (maintaining creation and disposal, when necessary, in various lifetime scopes).

So you doing almost everything "right", but just missing this "container" concept.

Lanorkin
  • 7,310
  • 2
  • 42
  • 60
  • Could you please give a link to the sample container? – Andrew Jul 02 '19 at 06:55
  • I think you _do_ use container; all you need to realize you need to use it _everywhere_. So instead of creating services by hand, you need to request their injection (almost?) everywhere. IoC containers provide integrations with frameworks like ASP.NET MVC, so framework will use container itself. I'm not familiar with Ninject, but their docs looks promising. For example this part about lifetime scopes https://github.com/ninject/Ninject/wiki/Object-Scopes and this one https://github.com/ninject/Ninject/wiki/Why-Use-Ninject in Extensions part provides a list to various frameworks integrations. – Lanorkin Jul 02 '19 at 07:04