I have a class where I am injecting two service dependencies. I am using Unity container.
public interface IOrganizer
{
void Method1();
void Method2();
void Method3();
}
public class Organizer : IOrganizer
{
private IService1 _service1;
private IService2 _service2;
public Organizer(Iservice1 service1, IService2 service2)
{
_service1 = service1;
_service2 = service2;
}
public void Method1()
{
/*makes use of _service1 and _service2 both to serve the purpose*/
}
public void Method2()
{
/*makes use of only _service1 to serve the purpose*/
}
public void Method3()
{
/*makes use of only _service2 to serve the purpose*/
}
}
While it all works, but somehow it smells because when when I am only invoking Method2
and Method3
, unity unnecessarily creates an instance of another not required service. The code snippet here is just sample for explanation purpose. In real situation object graph of these injected services itself is quite deep.
Is there a better way to design and address this kind of scenario?
I think your sense of smell is competent. Most people would happily code like this without a second thought. I do agree, though, that there's a few code smells in a design like outlined in the OP.
I'd like to point out that I use the term code smell as in Refactoring. It's an indication that something may not be right, and it might be worthwhile to investigate further. Sometimes, such investigation reveals that there are good reasons that the code is as it is, and you move on.
There's at least two separate smells in the OP. They're unrelated, so I'll treat each one separately.
Cohesion
A fundamental, but often forgotten concept of object-oriented design is that of cohesion. Think of it as a counter-force to separation of concerns. As Kent Beck once put it (the exact source escapes me, so I paraphrase), things that vary together, belong together, while things that vary independently should be separated.
Without the 'force' of cohesion, the 'force' of separation of concerns would pull code apart until you have extraordinarily small classes, and even simple business logic is spread across multiple files.
One way to look for cohesion, or lack thereof, is to 'count' how many class fields are being used by each method of a class. While only a crude indicator, it does trigger our sense of smell in the OP code.
Method1
uses both class fields, so is no cause for concern. Both Method2
and Method3
, on the other hand, use only half of the class fields, so we could view that as indication of poor cohesion - a code smell, if you will.
How can you address that? Again, I wish to emphasise that a smell isn't guaranteed to be bad. It's only a reason to investigate.
Still, if you want to address the issue, I can't think of any other way than breaking up the class into several smaller classes.
The Organizer
class in the OP implements the IOrganizer
interface, so technically, breaking up Organizer
is only possible if you can also break up the interface - although you could write a Facade, and then delegate each method to a separate class that implements that particular method.
Still, the presence of an interface emphasises the importance of the Interface Segregation Principle. I often see code bases exhibit this particular problem because the interfaces are too big. If at all possible, make the interfaces as small as possible. I tend to take it to the extreme and define only a single member on each interface.
From another of the SOLID principles, the Dependency Inversion Principle, follows that interfaces should be defined by the clients that use them, not the classes that implement them. Designing interfaces like that often enables you to keep them small, and to the point.
Recall also that a single class can implement multiple interfaces.
Performance
Another concern regarding the design in the OP is of performance, although I agree with NightOwl888's comment that you're likely in micro-optimisation territory.
In general, you can compose even large object graphs with confidence. As NightOwl888 also suggests in the comments above, if a dependency has Singleton lifetime, it makes little difference if you inject it, but then end up not using it.
Even if you can't give a dependency like _service2
Singleton lifetime, I again agree with NightOwl888 that object creation in .NET is fast to the point where you almost can't measure it. And as he also points out, Injection Constructors should be simple.
Even in the rare case where a dependency must have Transient lifetime, and for whatever reason creating an instance is expensive, you can always hide that dependency behind a Virtual Proxy, as I also describe in the article about object graphs.
How you configure all that in Unity, I no longer remember, but if Unity can't deal with that, choose another method of composition, preferably Pure DI.
As long as you're using Unit 3 or higher, you don't need to do anything special for resolving lazy.
You register your type like you normally would:
container.RegisteryType<IMyInterface>()...;
And then change the constructor to require lazy:
public class MyClass
{
public Lazy<IMyInterface> _service1;
public MyClass(Lazy<IMyInterface> service1)
{
_serivce1 = service1;
}
}
Then call whatever you method you need:
_service1.Value.MyMethod();