In this article, we will learn:
What is Dependency Inversion Principle (DIP)
What is Inversion of Control (IOC)
What is Service Locator?
What is Dependency Injection?
Difference between DIP and IOC (DIP vs IoC)
Difference between Dependency Injection and Service Locator (DI vs SL)
Many developers get confused with the term Dependency Injection. mainly on: What is Dependency Injection ? Why is it required? what is the mechanism behind Dependency Injection ?
In this article we will discuss all these terms in simple words.
What is Dependency Inversion Principle (DIP)
The Dependency Inversion principle refers to a specific form of decoupling software modules.It states:
- High-level modules should not depend on low-level modules. Both should depend on abstractions.
- Abstractions should not depend on details. Details should depend on abstractions
The Dependency Inversion principle (DIP) helps us to develop loosely couple code by ensuring that high-level modules depend on abstractions rather than concrete implementations of lower-level modules
What is Inversion Of Control (IOC)
Inversion of Control is a software design architecture where the framework controls the program flow. It means we are changing the control from normal way. IOC is used to increase modularity of the program and make it extensible.
To understand it better, lets look at an example.
When we are writing an ASP.net application, we are in ASP.net page life cycle but not in control where ASP.net is.
So as per the above diagram Dependency Injection (DI) and Service Locator (SL) are the ways of Implementing Inversion Of Control (IOC)
Difference between DIP and IOC (DIP VS IOC):
As stated earlier, DIP says high level module should not depend on low level module for abstraction and IOC provides abstraction.So if you want to make independent higher level module from the lower level module then you have to invert the control so that low level module will not control the interface and creation of the object.
Dependency Injection (DI):
- Dependency Injection is a design pattern allows us to write loose coupled code
- Dependency Injections helps us to manage future changes in code i.e. code maintainability
- Dependency Injection uses a builder object to initialize objects and provide the required dependencies to the object means it allows you to ‘inject’ a dependency from outside the class
Service Locator (SL):
- Service Locator is a software design pattern that allows us to develop loosely coupled code.
- It implements the DIP principle and easier to use with an existing codebase
- It introduces a locator object that is used to resolve dependencies within a class.
Difference between DI and SL (DI VS SL):
The Service Locator allows you to “resolve” a dependency within a class and the Dependency Injection allows you to “inject” a dependency from outside the class.
- When you use a service locator, every class will have a dependency on your service locator but in dependency injection,the dependency injector will typically be called only once at startup, to inject dependencies into the main class.
- The Service Locator pattern is easier to use in an existing codebase as it makes the overall design loosely coupled without forcing changes to the public interface. Code that is based on the Service Locator pattern is less readable than the equivalent code that is based on Dependency Injection.
Let’s look at an example:
public class Service
{
public void Serve()
{
Console.WriteLine("Service Called");
//To Do: Business logic
}
}
public class Client
{
private Service _service;
public Client()
{
this._service = new Service();
}
public void Start()
{
Console.WriteLine("Service Started");
this._service.Serve();
//To Do: Business logic
}
}The client class has a dependency on the Service class.
If you want to make it loosely coupled, you have to use IoC to make the more flexible and reusable it.
To implement the IoC, we have two main patterns: Service Locator and Dependency Injection.
Service Locator Implementation:
public interface IService
{
void Serve();
}
public class Service : IService
{
public void Serve()
{
Console.WriteLine("Service Called");
//To Do: Business Logic
}
}
public static class LocateService
{
public static IService _Service { get; set; }
public static IService GetService()
{
if (_Service == null)
_Service = new Service();
return _Service;
}
}
public class Client
{
private IService _service;
public Client()
{
this._service = LocateService.GetService();
}
public void Start()
{
Console.WriteLine("Service Started");
this._service.Serve();
//To Do: Business Logic
}
}
Sample Service Locator Implementation:
The Inversion happens in the constructor, by locating the Service that implements the IService-Interface.
The dependencies are assembled by a “Locator”.
class Program
{
static void Main(string[] args)
{
var client = new Client();
client.Start();
Console.ReadKey();
}
}
Dependency Injection Implementation:
public interface IService
{
void Serve();
}
public class Service : IService
{
public void Serve()
{
Console.WriteLine("Service Called");
//To Do: Business Logic
}
}
public class Client
{
private IService _service;
public Client(IService service)
{
this._service = service;
}
public void Start()
{
Console.WriteLine("Service Started");
this._service.Serve();
//To Do: Business Logic
}
}
Sample Builder Implementation:
The Injection happens in the constructor, by passing the Service that implements the IService-Interface.
The dependencies are assembled by a “Builder” and Builder responsibilities are as follows:
- knowing the types of each IService
- according to the request, send the abstract IService to the Client
class Program
{
static void Main(string[] args)
{
client = new Client(new Service());
client.Start();
Console.ReadKey();
}
}© 2016, Csharp Star. All rights reserved.




#
#
Please notice, you have a header in text
“What is Dependency Inversion Principle (DIP)”
but next sentence is starting from: “The Dependency Injection principle refers“.
I hope you mean DIP under header as well, not DI 🙂
#
updated now. Thanks for visiting.
#
Nice article and very helpfull to understand the Dependency Injection
#
Simple yet clear understanding of the concept…Thanks
#
it makes the overall design looser without forcing changes
should read
it makes the overall design loosely coupled without forcing changes
#
I very nice article describing dependence injection, which looks similar to polymorphic inheritance.
Both cases are unfortunately highly inefficient and should be used with care when considering such an implementation.
To use such techniques to “loosely couple” objects and\or sections of an application does not always play well with the realistic needs of any such development. The majority of applications are designed for what requirements exist in the present.
Such devices as dependency injection exist for the possibility of changes in the future that may promote additional but similar processes or brand new processes that are more easily implemented due to dependency injection.
There are those applications that do in fact require such possibilities for their development but not all and especially not many.
Nonetheless, many technical managers will espouse this type of development often not having a clue as to the requirements of it nor the complexities than can arise.
#
I’m going to have to call Steve on the carpet. Dependency Injection has nothing whatsoever to do with functional requirements. It satisfies quality attributes, or non-functional requirements. I would like to understand the rationale for the claims of inefficiency in the post. DI costs nothing but the time required to understand its proper use and value. Please refer to the book “Dependency Injection in .NET” by Mark Seeman for some excellent additional reading. If you write anything more complex than “Hello World” or expect it to last longer than the time it takes for your stakeholders to want extensions, then following the SOLID principals will serve you well. Please read about cohesion and coupling to get a feel for the value of this post and its roots. Steve, I hope you follow up with these suggestions. They’ll make your designs more useful, and your development life much easier.
#
There is a huge problem with the service locator, which is that the dependencies required for your class is not publicly visible, causing a code based where you have to dive into each class to understand the coherence with other objects. Also the service locator makes it hard to mock out dependencies when doing automated tests. The service locator does not reduce coupling, it merely hides it. Consider adding a decorator for a dependency, that would have to be set up in the service locator. But what if the service locator is used from multiple places, and it is only in some cases you need the decoration. Then suddenly you need logic about when to decorate exposed to the users of the service locator. Also the class where the service is needed would have to know that it needed a special version of an interface. This violates the dependency inversion principle that a class should only depend on abstraction and not in detailed knowledge of other classes.
However most dependency injection frameworks uses a service locator pattern for registration of mappings between classes and interfaces, for use when dependencies are to be created at runtime. So in some cases it makes sense to use the pattern.
I would always go with dependencies defined as interfaces, with a well defined purpose, using constructor injection and dependency definition set up with a DI container/framework to create high coherence and low coupling along with flexible application configuration.
#
I think you mean cohesion not coherence, and your point about hiding the coupling is not true. There is absolutely no way possible to remove all dependency from any engineering effort. By definition subsystems must affect the systems that incorporate them. Cohesion is generally explained stating “a software program designed to perform multiple tasks through multiple modules has a higher probability of having lower cohesion, which negatively affects its overall performance and effectiveness on computing machines”
The service locator enables the decorator that you advocate by permitting you to use a context to define the abstraction, thereby permitting you to compose it at run-time based on the purpose it is intended to serve.
Consider the pattern for the MS Rules Framework. You define your vocabularies and rules at design time. They can be added dynamically and are then stored in the policy cache. When a policy is evaluated by the rules engine, it looks at the cache for the definition of the policy using the evaluate method (if the customer is a frequent flier, then discount their flight by “rule = discount percent” calculated against the “vocabulary = subtotal”). If your ticketing application is running, its cache is updated dynamically when the new discount value is updated, or if a new rule is added for the policy that defines a new level of discount (i.e. frequent flyer and gold club member discount is discount + 1.5). This does not require exposing the logic. If you are truly “loosely coupled” then the test should be on the rule, and not the engine implementation of the rule, so testability is not impacted negatively, in fact it is enhanced greatly.
I do agree with the assertion that service locator is not a silver bullet, but is definitely not a construct to be avoided. Many times you cannot anticipate additional use cases for your component, and will not introduce this level of extensibility/maintainability because you always want to balance against complexity, but we should always be seeking use cases for extending components that we have built. By observing Open / Close and Single Responsibility principals we can generally identify when these patterns could be indicated.
We as engineers add value to our respective organizations by providing reusable components and extensions. This not only brings reduced cost of goods sold, it reduces customer total cost of ownership by supplying fix once fix everywhere, as well as improving the maturity and reliability of our components over time when we find and fix defects. When we compose our applications with these well matured components then they invariably solidify the applications that use them. This can only lead to good things for the reputation of our customers, our company and ourselves.