.NET and me Coding dreams since 1998!

19Jan/075

Dependency injection and service locator

To download Dependency Injection source code example, click here


Dependency injection is a interface programing technique which is based on altering class behavior without the changing the class internals. That's been done by coding against interface inside of the class and exposing interface definition to code external to the component. There are three types (different techniques) of making dependency injection: constructor DI, setter DI and interface DI.


Service locator is a design pattern similar to dependency injection in a meaning that allows altering the class behavior without altering the class code by coding against the interface inside of the class. The difference is that there's no direct exposure of interface to code outside of the class. Instead class is using "well known object" inside, to get from it desired interface implementation.


This helper well known object can be 3pt framework such as Structure Map or to build the framework by ourselves


Use case


The example I'll be using here is a kind of paycheck application which should write appropriate worker checks with appropriate amounts and title. Currently, there are two types of workers: Developer and Program manager, but in the future there could be some more. Developer has salary of $100 and the program manager has 3x bigger salary (like in real world, isn't it? :) )


The task is to make a paycheck application which would without the changing of the app code allow printing the paychecks for the different type of workers


Common implementation


There would be an IWorker interface defined like:


    public interface IWorker
    {
        string Name { get; set;}
        string SurName { get; set;}
        string Occupation { get;}
        decimal Salary { get;}
    }


And that interface would be implemented by Developer and ProjectManager classes


Developer class


public class Developer : IWorker
{
        public Developer(string name, string surname)
        {
            _name = name;
            _surname = surname;
        }

        #region IWorker Members

        private string _name;

        public string Name
        {
            get { return _name; }
            set { _name = value; }
        }

        private string _surname;
        public string SurName
        {
            get { return _surname; }
            set { _surname = value; }
        }

        public string Occupation
        {
            get { return "Developer"; }
        }

        public decimal Salary
        {
            get { return HelperMethods.GetSalary(TypeOfWorker.Developer); }
        }


}


Worker class


public class ProjectManager:IWorker
    {
        public ProjectManager(string name, string surname)
        {
            _name = name;
            _surname = surname;
        }

        #region IWorker Members

        private string _name;

        public string Name
        {
            get { return _name; }
            set { _name = value; }
        }

        private string _surname;
        public string SurName
        {
            get { return _surname; }
            set { _surname = value; }
        }

        public string Occupation
        {
            get { return "Project manager"; }
        }

        public decimal Salary
        {
            get { return HelperMethods.GetSalary(TypeOfWorker.ProjectManager); }
        }

        #endregion
    }


Both of classes, Developer and Manager for calculation of the Salary would use a helper method class GetSalaryMethod


public class HelperMethods
{
        public static decimal GetSalary(TypeOfWorker typeOfWorker)
        {
            decimal baseSalary = 100;
            if (typeOfWorker==TypeOfWorker.ProjectManager)
            {
                baseSalary = baseSalary*3;
// :)
            }
            return baseSalary;
        }
}


Our little class which would print the paychecks would be called PayCheck and it would have a void method PrintTheSalary()


Dependency injection - Constructor type


Constructor type dependency injection is based on a approach where the interface parameter which is referenced internally inside the class is been exposed through the constructor. In our example, class PayCheck would have a constructor which would have an IWorker parameter.


Implementation :

public class PayCheckCtor
{
      private IWorker _worker;

       public PayCheckCtor(IWorker worker)
        {
            _worker = worker;
        }

        public void PrintTheSalary()
        {
            Console.WriteLine(
                string.Format("Name:{0}, Surname: {1}, Title: {2}, Salary:{3}", _worker.Name,
               _worker.SurName, _worker.Occupation, _worker.Salary));
        }
}

Usage:


Developer developer = new Developer("Nikola", "Malovic");
ProjectManager manager = new ProjectManager("John", "Doe");

PayCheckCtor payCheck;
           
payCheck = new PayCheckCtor(developer);
payCheck.PrintTheSalary();

payCheck = new PayCheckCtor(manager);
payCheck.PrintTheSalary();


The good side of this approach is that in the moment when the code inside of the PayCheck class accessing the interface property, that property is guarantee to be initialized. The down side is that once injected value of the Interface can not be altered during the life time of the implementation (PayCheck)class  after the instance is been constructed.


Dependency injection - Setter type


Setter type of the DI pattern is enabling the injection of the interface implementation through the public property with set block. It is basically approach trying to cover the downsides of constructor based approach,


Implementation


public class PayCheckSet
{
        private IWorker _worker;
        public IWorker worker
        {
            set { _worker = value; }
        }

        public void PrintTheSalary()
        {
            Console.WriteLine(
                string.Format("Name:{0}, Surname: {1}, Title: {2}, Salary:{3}", _worker.Name,
                _worker.SurName, _worker.Occupation, _worker.Salary));
        }
}


Usage


Developer developer = new Developer("Nikola", "Malovic");
ProjectManager manager = new ProjectManager("John", "Doe");
PayCheckSet payCheck = new PayCheckSet();

payCheck.worker = developer;
payCheck.PrintTheSalary();
           
payCheck.worker = manager;
payCheck.PrintTheSalary();


The good side in this approach is that  it allows flexible changing of the interface implementation (on the fly). The down side is that when the code inside the class uses interface field, it is not guaranteed that the field wouldn't be null


Dependency injection - Interface type


Is a dependency injection technique which is a kind of explicit defined setter type DI. The object which would use the interface property has to support interface which defines the method which sets the interface property


Implementation


There would be an interface which defines setting of the interface property value


public interface ISetWorker
{
            void SetWorker(IWorker worker);
}


Implementation class (PayCheck) would have then to implement that interface


public class PayCheckIntf : ISetWorker
{
        private IWorker _worker;

        public void SetWorker(IWorker worker)
        {
            _worker = worker;
        }
       
        public void PrintTheSalary()
        {
            Console.WriteLine(
                string.Format("Name:{0}, Surname: {1}, Title: {2}, Salary:{3}", _worker.Name,
               _worker.SurName, _worker.Occupation, _worker.Salary));
        }
}


Usage


Developer developer = new Developer("Nikola", "Malovic");
ProjectManager manager = new ProjectManager("John", "Doe");

PayCheckIntf
payCheck = new PayCheckIntf();

payCheck.SetWorker(developer);
payCheck.PrintTheSalary();

payCheck.SetWorker(manager);
payCheck.PrintTheSalary();


Service locator


For all three explained dependency injection techniques the common is the fact that they are ignorant completely about where from implementation of the interface comes and when it would be initialized.


Service locator is also a dependency injection technique, but the decision about the way and moment of the implementation is moved to the implementation class itself (instead of outside interface implementation definition)


It could be even said that it is more  Dependency Absorption rather Dependency Injection :)


Implementation


Service locator is usually either 3pt framework or our special assembly, which can decide about the type of interface implementation based on some configuration settings or something similar. Basically the whole point in using service locator is to extract and abstract the interface implementation decision outside of the implementation class. It is not a good practice that the implementation class is calling the Service Locator method by providing some method (like a Factory does) because implementation class should be ignorant about the Service Locator implementation.


In this example, Service locator implementation uses Singleton with GetWorker and RegisterWorker methods


I didn't want to implement it fully with configuration settings of desired implementation, because it would introduce unnecessary complexity to sample.


public class WorkersServiceLocator
    {
        private static IWorker _worker;


        public static IWorker GetWorker()
        {
            return _worker;
        }

        public static void RegisterWorker(IWorker worker)
        {
            _worker = worker;
        }
    }


The PayCheck implementation using that ServiceLocator


public class PayCheckServLocator
    {
        public void PrintTheSalary()
        {
            ServiceLocator.IWorker _worker
                =ServiceLocator.WorkersServiceLocator.GetWorker();
            Console.WriteLine(
                string.Format("Name:{0}, Surname: {1}, Title: {2}, Salary:{3}", _worker.Name,
                _worker.SurName,  _worker.Occupation, _worker.Salary));
        }
    }


Usage


Developer developer = new Developer("Nikola", "Malovic");
ProjectManager manager = new ProjectManager("John", "Doe");

PayCheckServLocator payCheck = new PayCheckServLocator();

WorkersServiceLocator.RegisterWorker(developer);
payCheck.PrintTheSalary();

WorkersServiceLocator.RegisterWorker(manager);
payCheck.PrintTheSalary();


The good side in this approach is that  the control is allowed to control the moment of interface variable definition. It still allows flexible changing of the interface implementation because the service location internals are abstracted from  the implementing class level. The down side is that the implementation class is not so dumb any more and it has to take care about things outside of her scope (call to ServiceLocator method)


Conclusion:


Dependency injection is a very powerful technique very much used in Test Driven Development and I would speak more in near future about it in posts about TDD


 


Comments (5) Trackbacks (0)
  1. Thanks for this explanation. It is very usefull for me. I needed some easy to understand explanation for my

  2. I’ve just blog posted another blog post touching the same subject (Service locator vs. Dependency injection) from a different and a little bit more advanced angle

    blog.vuscode.com/…/dependency-injection-in-real-world.aspx

  3. This was a good article all the way up until you said, "Service Locator is a dependency injection technique".

    DI is a pattern like SL. However, DI is a pattern to achieve IoC. The roots of IoC is changing who is in control. A component that internally resolves it’s own dependencies is in control (SL style). This is the traditional way. A component that is given dependencies is NOT in control (DI style). This is IoC in the context of dependency resolution.  

    DI achieves IoC, SL does not.

  4. Json,

    you are right from pattern point of view but…

    Applying DI without the help of IoC container is quite an overkill and lead to broken encapsulation and if you think about DI in context of IoC containers you would see that each one of the IoC containers performing DI (Unity, StructureMap, Windsor, Ninject etc) have allways a ServiceLocator class which you use to register, retrieve your services.

    IMHO, In that context SL could be called as a technique of performing DI altought I am aware it is Fowler POEA pattern

    Please check out some of my more recent post presenting my views on the necessity of SL in big corps

    blog.vuscode.com/…/dependency-injection-in-real-world.aspx

  5. Hi, very interesting article. Simple and easy to understand.

    I have one question, what is the difference between the Factory and Service Locator?

    Thanks


Leave a comment

No trackbacks yet.