Monday, 6 July 2015

Dependency Injection Pattern

pendency Injection (DI) is a software design pattern that allow us to develop loosely coupled code. DI is a great way to reduce tight coupling between software components. DI also enables us to better manage future changes and other complexity in our software. The purpose of DI is to make code maintainable.
The Dependency Injection pattern 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.
For example, Suppose your Client class needs to use a Service class component, then the best you can do is to make your Client class aware of an IService interface rather than a Service class. In this way, you can change the implementation of the Service class at any time (and for how many times you want) without breaking the host code.
We can modify this code by the DI different ways. We have following different ways to implement DI :

Constructor Injection

  1. This is the most common DI.
  2. Dependency Injection is done by supplying the DEPENDENCY through the class’s constructor when instantiating that class.
  3. Injected component can be used anywhere within the class.
  4. Should be used when the injected dependency is required for the class to function.
  5. It addresses the most common scenario where a class requires one or more dependencies.
  1. public interface IService
  2. {
  3. void Serve();
  4. }
  5. public class Service : IService
  6. {
  7. public void Serve()
  8. {
  9. Console.WriteLine("Service Called");
  10. //To Do: Some Stuff
  11. }
  12. }
  13. public class Client
  14. {
  15. private IService _service;
  16. public Client(IService service)
  17. {
  18. this._service = service;
  19. }
  20. public void Start()
  21. {
  22. Console.WriteLine("Service Started");
  23. this._service.Serve();
  24. //To Do: Some Stuff
  25. }
  26. }
  27. class Program
  28. {
  29. static void Main(string[] args)
  30. {
  31. Client client = new Client(new Service());
  32. client.Start();
  33. Console.ReadKey();
  34. }
  35. }
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:
  1. knowing the types of each IService
  2. according to the request, feed the abstract IService to the Client

Property injection

  1. Also called Setter injection.
  2. Used when a class has optional dependencies, or where the implementations may need to be swapped. Different logger implementations could be used this way.
  3. May require checking for a provided implementation throughout the class(need to check for null before using it).
  4. Does not require adding or modifying constructors.
  1. public interface IService
  2. {
  3. void Serve();
  4. }
  5.  
  6. public class Service : IService
  7. {
  8. public void Serve()
  9. {
  10. Console.WriteLine("Service Called");
  11. //To Do: Some Stuff
  12. }
  13. }
  14.  
  15. public class Client
  16. {
  17. private IService _service;
  18.  
  19. public IService Service
  20. {
  21. set
  22. {
  23. this._service = value;
  24. }
  25. }
  26.  
  27. public void Start()
  28. {
  29. Console.WriteLine("Service Started");
  30. this._service.Serve();
  31. //To Do: Some Stuff
  32. }
  33. }
  34. class Program
  35. {
  36. static void Main(string[] args)
  37. {
  38. Client client = new Client();
  39. client.Service = new Service();
  40. client.Start();
  41.  
  42. Console.ReadKey();
  43. }
  44. }

Method injection

  1. Inject the dependency into a single method, for use by that method.
  2. Could be useful where the whole class does not need the dependency, just the one method.
  3. Generally uncommon, usually used for edge cases.
  1. public interface IService
  2. {
  3. void Serve();
  4. }
  5.  
  6. public class Service : IService
  7. {
  8. public void Serve()
  9. {
  10. Console.WriteLine("Service Called");
  11. //To Do: Some Stuff
  12. }
  13. }
  14.  
  15. public class Client
  16. {
  17. private IService _service;
  18.  
  19. public void Start(IService service)
  20. {
  21. this._service = service;
  22. Console.WriteLine("Service Started");
  23. this._service.Serve();
  24. //To Do: Some Stuff
  25. }
  26. }
  27. class Program
  28. {
  29. static void Main(string[] args)
  30. {
  31. Client client = new Client();
  32. client.Start(new Service());
  33.  
  34. Console.ReadKey();
  35. }
  36. }

Key points about DI

  1. Reduces class coupling
  2. Increases code reusing
  3. Improves code maintainability
  4. Improves application testing

Façade defines

Definition

Provide a unified interface to a set of interfaces in a subsystem. Façade defines a higher-level interface that makes the subsystem easier to use.

Frequency of use:
High





UML class diagram







Participants


    The classes and objects participating in this pattern are:
  • Facade   (MortgageApplication)
    • knows which subsystem classes are responsible for a request.
    • delegates client requests to appropriate subsystem objects.
  • Subsystem classes   (Bank, Credit, Loan)
    • implement subsystem functionality.
    • handle work assigned by the Facade object.
    • have no knowledge of the facade and keep no reference to it.



Structural code in C#


This structural code demonstrates the Facade pattern which provides a simplified and uniform interface to a large subsystem of classes.
  1. using System;

  2. namespace DoFactory.GangOfFour.Facade.Structural
  3. {
  4.   /// <summary>
  5.   /// MainApp startup class for Structural
  6.   /// Facade Design Pattern.
  7.   /// </summary>
  8.   class MainApp
  9.   {
  10.     /// <summary>
  11.     /// Entry point into console application.
  12.     /// </summary>
  13.     public static void Main()
  14.     {
  15.       Facade facade = new Facade();

  16.       facade.MethodA();
  17.       facade.MethodB();

  18.       // Wait for user
  19.       Console.ReadKey();
  20.     }
  21.   }

  22.   /// <summary>
  23.   /// The 'Subsystem ClassA' class
  24.   /// </summary>
  25.   class SubSystemOne
  26.   {
  27.     public void MethodOne()
  28.     {
  29.       Console.WriteLine(" SubSystemOne Method");
  30.     }
  31.   }

  32.   /// <summary>
  33.   /// The 'Subsystem ClassB' class
  34.   /// </summary>
  35.   class SubSystemTwo
  36.   {
  37.     public void MethodTwo()
  38.     {
  39.       Console.WriteLine(" SubSystemTwo Method");
  40.     }
  41.   }

  42.   /// <summary>
  43.   /// The 'Subsystem ClassC' class
  44.   /// </summary>
  45.   class SubSystemThree
  46.   {
  47.     public void MethodThree()
  48.     {
  49.       Console.WriteLine(" SubSystemThree Method");
  50.     }
  51.   }

  52.   /// <summary>
  53.   /// The 'Subsystem ClassD' class
  54.   /// </summary>
  55.   class SubSystemFour
  56.   {
  57.     public void MethodFour()
  58.     {
  59.       Console.WriteLine(" SubSystemFour Method");
  60.     }
  61.   }

  62.   /// <summary>
  63.   /// The 'Facade' class
  64.   /// </summary>
  65.   class Facade
  66.   {
  67.     private SubSystemOne _one;
  68.     private SubSystemTwo _two;
  69.     private SubSystemThree _three;
  70.     private SubSystemFour _four;

  71.     public Facade()
  72.     {
  73.       _one = new SubSystemOne();
  74.       _two = new SubSystemTwo();
  75.       _three = new SubSystemThree();
  76.       _four = new SubSystemFour();
  77.     }

  78.     public void MethodA()
  79.     {
  80.       Console.WriteLine("\nMethodA() ---- ");
  81.       _one.MethodOne();
  82.       _two.MethodTwo();
  83.       _four.MethodFour();
  84.     }

  85.     public void MethodB()
  86.     {
  87.       Console.WriteLine("\nMethodB() ---- ");
  88.       _two.MethodTwo();
  89.       _three.MethodThree();
  90.     }
  91.   }
  92. }
  93.  

Output
MethodA() ----
SubSystemOne Method
SubSystemTwo Method
SubSystemFour Method

MethodB() ----
SubSystemTwo Method
SubSystemThree Method





Real-world code in C#


This real-world code demonstrates the Facade pattern as a MortgageApplication object which provides a simplified interface to a large subsystem of classes measuring the creditworthyness of an applicant.
  1. using System;

  2. namespace DoFactory.GangOfFour.Facade.RealWorld
  3. {
  4.   /// <summary>
  5.   /// MainApp startup class for Real-World
  6.   /// Facade Design Pattern.
  7.   /// </summary>
  8.   class MainApp
  9.   {
  10.     /// <summary>
  11.     /// Entry point into console application.
  12.     /// </summary>
  13.     static void Main()
  14.     {
  15.       // Facade
  16.       Mortgage mortgage = new Mortgage();

  17.       // Evaluate mortgage eligibility for customer
  18.       Customer customer = new Customer("Ann McKinsey");
  19.       bool eligible = mortgage.IsEligible(customer, 125000);

  20.       Console.WriteLine("\n" + customer.Name +
  21.           " has been " + (eligible ? "Approved" : "Rejected"));

  22.       // Wait for user
  23.       Console.ReadKey();
  24.     }
  25.   }

  26.   /// <summary>
  27.   /// The 'Subsystem ClassA' class
  28.   /// </summary>
  29.   class Bank
  30.   {
  31.     public bool HasSufficientSavings(Customer c, int amount)
  32.     {
  33.       Console.WriteLine("Check bank for " + c.Name);
  34.       return true;
  35.     }
  36.   }

  37.   /// <summary>
  38.   /// The 'Subsystem ClassB' class
  39.   /// </summary>
  40.   class Credit
  41.   {
  42.     public bool HasGoodCredit(Customer c)
  43.     {
  44.       Console.WriteLine("Check credit for " + c.Name);
  45.       return true;
  46.     }
  47.   }

  48.   /// <summary>
  49.   /// The 'Subsystem ClassC' class
  50.   /// </summary>
  51.   class Loan
  52.   {
  53.     public bool HasNoBadLoans(Customer c)
  54.     {
  55.       Console.WriteLine("Check loans for " + c.Name);
  56.       return true;
  57.     }
  58.   }

  59.   /// <summary>
  60.   /// Customer class
  61.   /// </summary>
  62.   class Customer
  63.   {
  64.     private string _name;

  65.     // Constructor
  66.     public Customer(string name)
  67.     {
  68.       this._name = name;
  69.     }

  70.     // Gets the name
  71.     public string Name
  72.     {
  73.       get { return _name; }
  74.     }
  75.   }

  76.   /// <summary>
  77.   /// The 'Facade' class
  78.   /// </summary>
  79.   class Mortgage
  80.   {
  81.     private Bank _bank = new Bank();
  82.     private Loan _loan = new Loan();
  83.     private Credit _credit = new Credit();

  84.     public bool IsEligible(Customer cust, int amount)
  85.     {
  86.       Console.WriteLine("{0} applies for {1:C} loan\n",
  87.         cust.Name, amount);

  88.       bool eligible = true;

  89.       // Check creditworthyness of applicant
  90.       if (!_bank.HasSufficientSavings(cust, amount))
  91.       {
  92.         eligible = false;
  93.       }
  94.       else if (!_loan.HasNoBadLoans(cust))
  95.       {
  96.         eligible = false;
  97.       }
  98.       else if (!_credit.HasGoodCredit(cust))
  99.       {
  100.         eligible = false;
  101.       }

  102.       return eligible;
  103.     }
  104.   }
  105. }
  106.  
  107.  

Output
Ann McKinsey applies for $125,000.00 loan

Check bank for Ann McKinsey
Check loans for Ann McKinsey
Check credit for Ann McKinsey

Ann McKinsey has been Approved