Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generic Vs Dependency injection

Is there any difference between Generic Classes and Dependency injection ? Are they not ways to implement Inversion of Control

Is generic class not a way to implement Dependency Injection with added benefits of compile time safety ?

For Example, if I have a node class, then I can define as following

class Node<T> where T : ISomeInterface
{
  ..
  ..
}

class Node
{
   ISomeInterface obj
   public Node(ISomeInterface inject)
   {
       obj = inject;
   }
}

UPDATE 2 With New

class Node<T> where T : ISomeInterface, new()
{
  ISomeInterface obj
  public Node()
  {
     obj = new T();
  }
}

Update 3 @akim : I have made the example that you asked for using Generics Repository using Generics

Interface IRepository 
{   
      public DataTable GetAll();
}

public class ProductRep : IRepository
{ 
       public DataTable GetAll()
       {
            //implementation
       }
}

public class MockProductRep : IRepository
{ 
       public DataTable GetAll()
       {
            //mock implementation
       }
}

public class Product<T> where T : IRepository, new()
{
    IRepository repository = null
     public Product()
     {
       repository = new T();
     }
    public List<Product> GetProduct()
    {
      DataTable prodlst =  repository.GetAll();
      //convert to List of products now
    }
}


//so while using the Product class, client would Supply ProductRep class and in NUnit you //would supply MockProductRep class

Product<ProductRep> obj = new ProductRep<ProductRep>();
List<Product> lst = obj.GetProduct();

//in NUnit
Product<MockProductRep> obj = new ProductRep<MockProductRep>();
List<Product> lst = obj.GetProduct();
like image 659
Anand Avatar asked Jul 30 '12 04:07

Anand


People also ask

What are the three types of dependency injection?

There are three main styles of dependency injection, according to Fowler: Constructor Injection (also known as Type 3), Setter Injection (also known as Type 2), and Interface Injection (also known as Type 1).

What is the difference between dependency injection and IOC?

Dependency Injection is the method of providing the dependencies and Inversion of Control is the end result of Dependency Injection. IoC is a design principle where the control flow of the program is inverted. Dependency Injection is one of the subtypes of the IOC principle.

What is the alternative to dependency injection?

An alternative to dependency injection is using a service locator. The service locator design pattern also improves decoupling of classes from concrete dependencies. You create a class known as the service locator that creates and stores dependencies and then provides those dependencies on demand.

What are the advantages of using generic?

Generics shift the burden of type safety from you to the compiler. There is no need to write code to test for the correct data type because it is enforced at compile time. The need for type casting and the possibility of run-time errors are reduced. Better performance.


2 Answers

They are not the same. Generic types allow you to define functionality that can be applied to a wide range of other types. However when you instantiate a generic class, the compiler makes a reference to the actual types that were passed as generic parameters. So the declaration is static and cannot change after compilation. For example, I can write code that instantiates your Node class:

Node<SomeImplementation> node1 = new Node<SomeImplementation>();
Node<SomeOtherImplementation> node2 = new Node<SomeOtherImplementation>();

I am reusing your Node class in different scenarios, but once I have compiled my assembly, I cannot change the generic type of my variables (node1 and node2).

Dependency Injection (and IoC containers), on the other hand, allow you to change the functionality of your app at runtime. You can use Dependency Injection to swap out one implementation of ISomeInterface with a totally different implementation at runtime. For example, in your second node class, I can use an IoC container to create the Node class... something like:

Node n = Container.Create<Node>();

The IoC container then figures out how to instantiate the Node class based on some configuration. It determines that the constructor needs an implementation of ISomeInterface, and it knows how to build an implementation at runtime. I can change my configuration for the IoC container and execute the same assembly/code and a different implementation of ISomeInterface will be created and passed to the constructor of Node.

This is useful in unit tests, because you can mock out certain parts of your application so that one specific class can be tested. For example, you may want to test some business logic that usually accesses a database. In your unit test, you can mock your data access logic and inject new functionality that returns 'static' data that is needed to test each particular business case. This breaks your tests dependency on the database and allows for more accurate/maintainable testing.

Edit

With regards to your update, the parameter-less constructor restriction may not always be desired. You may have a class (written by you or a third party) that requires parameters. Requiring a class to implement a parameter-less constructor may effect the integrity of the application. The idea behind the DI pattern is that your Node class doesn't need to know how the class was actually created.

Suppose you had many layers of classes/dependencies. With generic types, it might look like this:

class MyClass<T>
    where T : IUtilityClass
{
    ...
}

class UtilityClass<T> : IUtilityClass
    where T : IAnotherUtilityClass
{
    ...
}

class AnotherUtilityClass : IAnotherUtilityClass
{
    ...
}

In this case, MyClass uses UtilityClass, and UtilityClass depends on AnotherUtilityClass. So when you declare MyClass, you must know every dependency down the line... not just the dependencies of MyClass, but also the dependencies of UtilityClass. This declaration looks something like this:

MyClass<UtilityClass<AnotherUtilityClass>> myTestClass =
    new MyClass<UtilityClass<AnotherUtilityClass>>();

This would get cumbersome as you add more and more dependencies. With DI, your caller doesn't need to know about any of the nested dependencies because the IoC container automatically figures them out. You just do something like this:

MyClass myTestClass = Container.Create<MyClass>();

There's no need to know anything about the details of MyClass or it's utility classes.

There are usually other benefits to IoC containers as well, for example many of them provide forms of Aspect Oriented Programming. They also allow you to specify the lifetime of an object, so an object could be a singleton (only one instance will be created, and the same instance will be returned to all callers).

like image 91
Glen Hughes Avatar answered Oct 19 '22 22:10

Glen Hughes


Generics introduce the concept of type parameters, which make it possible to design classes and methods that defer the specification of one or more types until the class or method is declared and instantiated by code msdn. And generics with all their restrictions and check are applied during compile time using static analysis.

In other hand, Dependency injection is a software design pattern that allows a choice of component to be made at run-time rather than compile time wiki. And object coupling is bound at run time by an assembler object and is typically not known at compile time using static analysis wiki.

Answer on your question: one applied at compile time using static analysis, another applied at run time using XML or in-code configuration (it should be also valid for compile). Using Dependency injection decision about binding will be postponed until more information or configuration will be available from the context. So generics and dependency injection are different, and used for different purpose.

Sample #3 answer

Let's move one step further and provide Repository<Entity> to Controller and think about it usage. How are you going to implement controler's constructor:

public ControlFreakController<Repository<Entity>>()
{
    this.repository = new Repository<Entity>(); // here is a logical problem
}

or

public ControllerWithInjection(IRepository repository)
{
   this.repository = repository;
}

And how will you cover ControlFreakController with tests, if it depends on Repository<Entity> (literally hardcoded)? What if Repository<Entity> has no default constructor, and has its own dependencies and life time (for example, there should be one and only one repository rep HTTP request)? What if next day it will be required to audit work with Repository<Entity>?

like image 3
Akim Avatar answered Oct 20 '22 00:10

Akim