Dependency Injection and internal helper classes
Asked Answered
W

2

6

I use Castle Windsor, but I guess this applies to all DI containers...

I often find myself creating internal helper classes and injecting these into other classes. (Actually Windsor doesn't support internal ctrs so I typically end up making the helper classes public, which is my first "code smell").

The helper class may have a number of dependencies of its own, of types already registered with Windsor, so it makes sense (to me) to register the helper class with Windsor too, so I can inject it into the classes that need it. E.g.

public MyService : IService
{
    public MyService(MyHelper helper, other dependencies...)
    {
    }
}

After reading a few articles I'm starting to wonder if this is "misusing" Windsor, or just generally bad code design. If that's the case, how should I deal with helper classes?

Wireworm answered 20/7, 2017 at 7:55 Comment(4)
Registering dependencies without interfaces: #3132437Terrigenous
What do the internal helpers do?Scaler
@Scaler one example might be a class that analyses some numeric data passed to it, then writes the results to a file in JSON format. This in turn may have dependencies on classes that provide math functions and JSON formatting. In this scenario I would register the "analysis" class with Windsor, and possibly the others too (if they had dependencies of their own). If a "helper" class has no dependencies then I don't usually bother registering it with Windsor, and instead leave it up to the consuming classes to "new" it up themselves.Wireworm
Do not feel scared if you start combining small components in different configurations behind different interfaces. @Steven explanation is correct.Hershey
A
7

I often find myself creating internal helper classes and injecting these into other classes.

This is a common refactoring technique called Facade Services:

Facade Service hides the aggregate behavior behind a new abstraction.

As for your question about internal classes:

making the helper classes public, which is my first "code smell").

Not at all. There is nothing smelly about public classes. If you follow the rule "program to interfaces" there is no problem if the implementation is public. This simplifies testing, since unit tests will depend on the class directly.

Long story story, you are not misusing DI or a DI Container. If you are encapsulating the behavior inside the helper class, you are doing the right thing. Hard thing however is to find out what the best way to encapsulate behavior is in a way that makes sense from a business perspective. But while doing so, it might lead you to new insides and new business concepts.

Aerodyne answered 20/7, 2017 at 8:39 Comment(5)
That's good to hear. I've read a few articles over the years about DI, and Castle Windsor in particular, where I was (perhaps mistakenly) getting the feeling that it was intended to be used with public APIs and interfaces, rather than "all the internal stuff". I'd been having a recent crisis of conscience worrying that I had been "over-using" Windsor all this time!Wireworm
You don't always have to register "all internal stuff" in the container. The distinction we typically make is whether or not a dependency is volatile or not. If it's behavior is impure or you wish to decorate, mock or intercept its creation, it is volatile and this means you should inject it.Aerodyne
I do unit test, so the ability to mock these helpers is great. However another reason for injecting them is because they often have dependencies of their own, also registered with the DI. I suspect the problem is that over the course of the project I've treated too many of these internal classes as "liable to change", when in fact they never will, resulting in me going overboard by registering so many of them with the DI (although it sounds like there's nothing wrong with doing this, per se).Wireworm
Steven, What do you mean in the phrase If it's behavior is impure .. it is volatile - what does "impure behavior" mean?Dote
Impure is the opposite of pure. It means that the code has side effects or does I/O.Aerodyne
A
1

it makes sense (to me) to register the helper class with Windsor too, so I can inject it into the classes that need it

Spot on :)

Dependency injection is a technique where one object supplies the dependencies of another object.

It makes no difference if the dependency is an interface or a class (or a string, or an int...) - it is still a "dependency". Helper or utility classes are very common aids, but you may find it useful to program to an interface, as for example this means we can mock them for testing purposes, or substitute one implementation for another without affecting the services that depend upon them.

Anaximander answered 20/7, 2017 at 8:27 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.