I was recently having a debate about the Dependency Inversion Principle, Inversion of Control and Dependency Injection. In relation to this topic we w
Summing up the question:
We have the ability for a Service to instantiate its own dependencies.
Yet, we also have the ability for a Service to simply define abstractions, and require an application to know about the dependent abstractions, create concrete implementations, and pass them in.
And the question is not, "Why we do it?" (Because we know there is a huge list of why). But the question is, "Doesn't option 2 break encapsulation?"
My "pragmatic" answer
I think Mark is the best bet for any such answers, and as he says: No, encapsulation isn't what people think it is.
Encapsulation is hiding away implementation details of a service or abstraction. A Dependency isn't an implementation detail. If you think of a service as a contract, and its subsequent sub-service dependencies as sub-contracts (etc etc chained along), then you really just end up with one huge contract with addendums.
Imagine I'm a caller and I want to use a legal service to sue my boss. My application would have to know about a service that does so. That alone breaks the theory that knowing about the services/contracts required to accomplish my goal is false.
The argument there is... yeah, but I just want to hire a lawyer, I don't care about what books or services he uses. I'll get some random dood off the interwebz and not care about his implementation details... like so:
sub main() {
LegalService legalService = new LegalService();
legalService.SueMyManagerForBeingMean();
}
public class LegalService {
public void SueMyManagerForBeingMean(){
// Implementation Details.
}
}
But it turns out, other services are required to get the job done, such as understanding workplace law. And also as it turns out... I am VERY Interested in the contracts that lawyer is signing under my name and the other stuff he's doing to steal my money. For example... Why the hell is this internet lawyer based in South Korea? How will THAT help me!?!? That isn't an implementation detail, that's part of a dependency chain of requirements I'm happy to manage.
sub main() {
IWorkLawService understandWorkplaceLaw = new CaliforniaWorkplaceLawService();
//IWorkLawService understandWorkplaceLaw = new NewYorkWorkplaceLawService();
LegalService legalService = new LegalService(understandWorkplaceLaw);
legalService.SueMyManagerForBeingMean();
}
public interface ILegalContract {
void SueMyManagerForBeingMean();
}
public class LegalService : ILegalContract {
private readonly IWorkLawService _workLawService;
public LegalService(IWorkLawService workLawService) {
this._workLawService = workLawService;
}
public void SueMyManagerForBeingMean() {
//Implementation Detail
_workLawService.DoSomething; // { implementation detail in there too }
}
}
Now, all I know is that I have a contract which has other contracts which might have other contracts. I am very well responsible for those contracts, and not their implementation details. Though I am more than happy to sign those contracts with concretions that are relevant to my requirements. And again, I don't care about how those concretions do their jobs, as long as I know I have a binding contract that says we exchange information in some defined way.