Thursday, February 7, 2008

Dependency Injection

Every software entity is dependent on zero, one or more software entities for its functioning and providing its services to the consumer (calling entity). Dependency Injection is a method of injecting the dependencies in the serving class by either the caller or an IoC container.

Instead of the serving component creating dependencies by its own, it is the caller or the IoC container which is responsible for creating those dependencies and injecting it into the component.

Ways of declaring dependencies

Component declares its dependencies using one or more of the methods of declaring dependencies. Below are the ways a component can declare its dependencies:


  1. Constructor Injection: The component declares the dependencies as a parameter to the constructor. All the mandatory dependencies can be captured in the constructor as read-only dependencies. Optional dependencies can be captured by providing the parameterized constructors.
  2. Parameter Injection: To provide dynamic configuration and modifications of dependencies at runtime, parameter injection can be used. Usually parameter injection is used for optional dependencies.
  3. Method Injection: If the dependency is required only for a limited scope i.e. only for a specific method in the component then method injection becomes an appropriate choice. In this type of injection, dependency is injected as a parameter of a method.

Benefits

  1. Interface Driven Development: Dependencies are declared using interfaces or abstract classes. Varying implementation of the interfaces can be used. This promotes extensible and flexible design.
  2. Loose Coupling: Loose coupling is achieved by dependency inversion. The component depends on the interface and any implementation of the interface can be substituted for the dependency.
  3. Parallel Development: The component does not require that its dependencies are already in place and implemented. It only requires an interface of the dependent component. Infrastructure team can publish well thought and properly designed interfaces to the application team. Application team can start developing business logic without waiting for the actual implementation of the dependency to available.
  4. Promotes Unit Testing: A UUT (Unit Under Test) should be isolated from the consequences its dependencies to get the maximum benefit of unit testing. Dependency Injection provides a way to isolate the unit under test by providing stubs or mocks for the dependencies.
  5. Configurability: Using IoC container declarative and programmatic configurability can be achieved. Declarative configuration supported by IoC container can be used to configure what dependencies get injected in the component. Application can be configured declaratively without the need for compilation.
  6. Adherence to Single Responsibility Principle: It smells of breaking a SRP (Single Responsibility Principle) when the component declares more than three mandatory dependencies. The smell may denote a problem where the component has more than multiple responsibilities or lack of cohesion. This type of smell can be mitigated by applying refactoring to introduce new type and moving some of the unrelated responsibility to new type.

Limitations

  1. Disclosing Internals: The component reveals its internals by declaring dependencies. The calling component has to have knowledge of creating the dependencies and injecting in the server component.
  2. Dependency on IoC Container: It creates a dependency on IoC container. It changes the way how you design your classes.
  3. Over Engineering: If not properly thought, Dependency Injection and use of IoC container may lead to designs which are over engineered. A judgment call is to be made whether such flexibility of declarative configurability is required or not.

No comments: