How to avoid Dependency Injection constructor madn

2018-12-31 06:45发布

I find that my constructors are starting to look like this:

public MyClass(Container con, SomeClass1 obj1, SomeClass2, obj2.... )

with ever increasing parameter list. Since "Container" is my dependency injection container, why can't I just do this:

public MyClass(Container con)

for every class? What are the downsides? If I do this, it feels like I'm using a glorified static. Please share your thoughts on IoC and Dependency Injection madness.

9条回答
伤终究还是伤i
2楼-- · 2018-12-31 07:19

What dependency injection framework are you using? Have you tried using setter based injection instead?

The benefit for constructor based injection is that it looks natural for Java programmers who don't use DI frameworks. You need 5 things to initialize a class then you have 5 arguments for your constructor. The downside is what you have noticed, it gets unwieldy when you have lots of dependencies.

With Spring you could pass the required values with setters instead and you could use @required annotations to enforce that they are injected. The downside is that you need to move the initialization code from the constructor to another method and have Spring call that after all the dependencies are injected by marking it with @PostConstruct. I'm not sure about other frameworks but I assume they do something similar.

Both ways work, its a matter of preference.

查看更多
墨雨无痕
3楼-- · 2018-12-31 07:20

I came across a similar question about constructor based dependency Injection and how complex it was getting to pass in all the dependencies.

One of the approach, I have used in past is to use the application facade pattern using a service layer. This would have a coarse API. If this service depends on repositories, It would use a setter injection of the private properties. This requires creating an abstract factory and moving the logic of creating the repositories into a factory.

Detailed code with explanation can be found here

Best practices for IoC in complex service layer

查看更多
心情的温度
4楼-- · 2018-12-31 07:20

I read this whole thread, twice, and I think people are responding by what they know, not by what is asked.

JP's original question looks like he's constructing objects by sending a resolver, and then a bunch of classes, but we're assuming that those classes/objects are themselves services, ripe for injection. What if they are not?

JP, if you're looking to leverage DI and desire the glory of mixing injection with contextual data, none of these patterns (or supposed "anti-patterns") specifically address that. It actually boils down to using a package which will support you in such an endeavor.

Container.GetSevice<MyClass>(someObject1, someObject2)

... this format is rarely supported. I believe the difficulty of programming such support, added to the miserable performance that would be associated with the implementation, makes it unattractive for opensource developers.

But it should be done, because I should be able to create and register a factory for MyClass'es, and that factory should be able to receive data/input that aren't pushed into being a "service" just for the sake of passing data. If "anti-pattern" is about negative consequences, then forcing the existence of artificial service types for passing data/models is certainly negative (on par with your feeling about wrapping up your classes into a container. Same instinct applies).

There are framework that may help, though, even if they look a bit ugly. For example, Ninject:

Creating an instance using Ninject with additional parameters in the constructor

That's for .NET, is popular, and is still nowhere as clean as it should be, but I'm sure there's something in whatever language you choose to employ.

查看更多
像晚风撩人
5楼-- · 2018-12-31 07:21

The difficulty of passing in the parameters is not the problem. The problem is that your class is doing too much, and should be broken down more.

Dependency Injection can act as an early warning for classes getting too big, specifically because of the increasing pain of passing in all of the dependencies.

查看更多
谁念西风独自凉
6楼-- · 2018-12-31 07:23

You are right that if you use the container as a Service Locator, it's more or less a glorified static factory. For lots of reasons I consider this an anti-pattern.

One of the wonderful benefits of Constructor Injection is that it makes violations of the Single Responsibility Principle glaringly obvious.

When that happens, it's time to refactor to Facade Services. In short, create a new, more coarse-grained interface that hides the interaction between some or all of the fine-grained dependencies you currently require.

查看更多
梦醉为红颜
7楼-- · 2018-12-31 07:23

Injecting the container is a shortcut that you will ultimately regret.

Over injection is not the problem, it is usually a symptom of other structural flaws, most notably separation of concerns. This is not one problem but can have many sources and what makes this so difficult to fix is that you are going to have to deal with all of them, sometimes at the same time (think of untangling spaghetti).

Here is an incomplete list of the things to look out for

Poor Domain Design (Aggregate root’s …. etc)

Poor separation of concerns (Service composition, Commands, queries) See CQRS and Event Sourcing.

OR Mappers (be careful, these things can lead you into trouble)

View Models and other DTO’s (Never reuse one, and try to keep them to a minimal !!!!)

查看更多
登录 后发表回答