Sunday, June 20, 2021

C# Design Pattern - Dependency Injection Pattern


Dependency
is all about dependence of one class upon another class. More the dependent one class is on other class, more they are said to be tightly coupled. In such situation, a change in independent class leads to change in the dependent class. The software architecture aims to develop loosely coupled system to allow easy maintenance and extensibility of the system.

Why Loosely Coupled System
Software development is a costly affair. The tightly coupled system or higher dependency of classes in a system makes it difficult to modify the software when business logic changes. The change of business logic is a very common phenomenon. Therefore, the software components should be loosely coupled.

The client class uses the service of service class but it might be possible that some of the services of service class can be delegated to another class. The class which is delegated those tasks is called Injector class. The injector class creates the objects of service class which are consumed by the client class and injects them into the client class. Such injected objects are called dependency objects. Dependency objects provide services. Dependency object is injected into dependent class. The injector class injects the dependency object into a class in three different ways. They are as follows.

Three Types of DI
  1. Through the constructor of client class i.e. Constructor Injector
  2. Through the public property of client class i.e. Property Injector
  3. Through the public method of client class i.e. Method Injector
First we see the example of tightly coupled system.
Data Access Layer (DAL) allows to access data from the database. It has different methods to access the data. In-memory data is used to do the same in below example.

using System;
using System.Collections.Generic;

namespace DI
{
    class Student
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public int Marks { get; set; }
    }
    //
    class StudentDAL
    {
        public List<Student> students = new List<Student>()
        {
            new Student(){Id=1,Name="Amit",Marks=80},
            new Student(){Id=2,Name="Rina",Marks=60},
            new Student(){Id=3,Name="Gaurav",Marks=75},
            new Student(){Id=4,Name="Mina",Marks=55}
        };
        public List<Student>  GetStudentsDAL()
        {
            return students;
        }
    }
    //service class
    class StudentBAL
    {
        public StudentDAL allStudents;
        public List<Student> GetStudentsListBAL()
        {
            allStudents = new StudentDAL();
            return allStudents.GetStudentsDAL();
        }
    }
    //client class
    class Program
    {
        static void Main(string[] args)
        {
            StudentBAL bal = new StudentBAL();
            var list = bal.GetStudentsListBAL();
            foreach (var student in list)
            {
                Console.WriteLine("Id: {0}, Name: {1}, Marks: {2}",student.Id,student.Name, student.Marks );
            }
            Console.ReadKey();
        }
    }
}

NOTE The StudentBAL class GetStudentsListBAL method is dependent on GetStudentsDAL. So, both classes StudentBAL and StudentDAL are tightly coupled.

Constructor Injector
Now, we see the example of Constructor Injector in the following example.
using System;
using System.Collections.Generic;

namespace DI
{
    public class Student
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public int Marks { get; set; }
    }

    public interface IStudentDAL
    {
        List<Student> GetStudentsDAL();
    }
    public class StudentDAL : IStudentDAL
    {
        public List<Student> students = new List<Student>()
        {
            new Student(){Id=1,Name="Amit",Marks=80},
            new Student(){Id=2,Name="Rina",Marks=60},
            new Student(){Id=3,Name="Gaurav",Marks=75},
            new Student(){Id=4,Name="Mina",Marks=55}
        };
        public List<Student>  GetStudentsDAL()
        {
            return students;
        }
    }
    //service class
    class StudentBAL
    {
        private IStudentDAL _allStudents;//Dependency Object injected here
        //create constructor
        public StudentBAL(IStudentDAL allStudents)
        {
            _allStudents = allStudents;
        }
        public List<Student> GetStudentsListBAL()
        {
            return _allStudents.GetStudentsDAL();
        }
    }
    //client class
    class Program
    {
        static void Main(string[] args)
        {
            StudentBAL studentBAL = new StudentBAL(new StudentDAL());
            List<Student> list = studentBAL.GetStudentsListBAL();
            foreach (var student in list)
            {
                Console.WriteLine("Id: {0}, Name: {1}, Marks: {2}",student.Id,student.Name, student.Marks );
            }
            Console.ReadKey();
        }
    }
}
Property Injector 
We take the above example again. We inject property of Independent entity i.e. IStudentDAL into StudentBAL upon which StudentBAL is dependent.

using System;
using System.Collections.Generic;

namespace DI
{
    public class Student
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public int Marks { get; set; }
    }

    public interface IStudentDAL
    {
        List<Student> GetStudentsDAL();
    }
    public class StudentDAL : IStudentDAL
    {
        public List<Student> students = new List<Student>()
        {
            new Student(){Id=1,Name="Amit",Marks=80},
            new Student(){Id=2,Name="Rina",Marks=60},
            new Student(){Id=3,Name="Gaurav",Marks=75},
            new Student(){Id=4,Name="Mina",Marks=55}
        };
        public List<Student>  GetStudentsDAL()
        {
            return students;
        }
    }
    //service class
    class StudentBAL
    {
        private IStudentDAL _allStudents; //Dependency Object injected here
        //get and set to initialize the property allStudents
        public IStudentDAL allStudents
        {
            get
            {
                if (allStudents != null)
                {
                    return _allStudents;
                }
                else
                {
                    throw new Exception("Student is not initialized.");
                }
            }
            set
            {
                this._allStudents = value;
            }

        }
        //removed the constructor from previous example
        public List<Student> GetStudentsListBAL()
        {
            return _allStudents.GetStudentsDAL();
        }
    }
    //client class
    class Program
    {
        static void Main(string[] args)
        {
            StudentBAL studentBAL = new StudentBAL();
            //BAL accesses DAL through property
            studentBAL.allStudents = new StudentDAL();
            List<Student> list = studentBAL.GetStudentsListBAL();
            foreach (var student in list)
            {
                Console.WriteLine("Id: {0}, Name: {1}, Marks: {2}",student.Id,student.Name, student.Marks );
            }
            Console.ReadKey();
        }
    }
}

Method Injector
Method Injector is similar to Constructor Injector. Constructor Injector code is edited to get the following code. The constructor is deleted. The constructor dependency object is now passed to GetStudentsListBAL method. In the client class, a new Dependency object is created as method argument during GetStudentsListBAL call. 
using System;
using System.Collections.Generic;

namespace DI
{
    public class Student
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public int Marks { get; set; }
    }

    public interface IStudentDAL
    {
        List<Student> GetStudentsDAL();
    }
    public class StudentDAL : IStudentDAL
    {
        public List<Student> students = new List<Student>()
        {
            new Student(){Id=1,Name="Amit",Marks=80},
            new Student(){Id=2,Name="Rina",Marks=60},
            new Student(){Id=3,Name="Gaurav",Marks=75},
            new Student(){Id=4,Name="Mina",Marks=55}
        };
        public List<Student> GetStudentsDAL()
        {
            return students;
        }
    }
    //service class
    class StudentBAL
    {
        //Dependency object reference passed to method as parameter
        public List<Student> GetStudentsListBAL(IStudentDAL allStudents)
        {
            return allStudents.GetStudentsDAL();
        }
    }
    //client class
    class Program
    {
        static void Main(string[] args)
        {
            StudentBAL studentBAL = new StudentBAL();
            //Dependency object passed to method as parameter
            List<Student> list = studentBAL.GetStudentsListBAL(new StudentDAL());
            foreach (var student in list)
            {
                Console.WriteLine("Id: {0}, Name: {1}, Marks: {2}", student.Id, student.Name, student.Marks);
            }
            Console.ReadKey();
        }
    }
}



No comments:

Post a Comment

Hot Topics