Dependency Injection and the Repository Design Pattern

Siddharth Phatarphod
3 min readMar 3, 2023

--

Source: https://stackify.com/wp-content/uploads/2018/06/Design-Patterns-Explained-%E2%80%93-Dependency-Injection-with-Code-Examples.png

Dependency Injection (DI) and the Repository design pattern are important concepts in software development that help make code more modular, testable and maintainable.

DI allows developers to remove hard-coded dependencies in a class by injecting them through constructor, property or method parameters.

The Repository design pattern provides a layer of abstraction between the data access layer and the business logic layer to separate them.

Dependency Injection (DI) and the Repository design pattern can work together to improve code modularity and maintainability.
The use of Dependency Injection with the Repository patterns alleviates its own benefits that include ease to write unit tests, extend the application, and switch between different data sources without modifying the business logic layer.

Classes at each layer of the architecture will have classes they need from lower layers injected into them. This introduces a layer of abstraction between the application and the repositories so that they can change more independently.

Dependency Injection has many benefits including the below:

  1. Loose coupling between components allowing developers to write highly modular, testable, and maintainable code.
  2. Testability: Dependency Injection makes it easier to write unit tests for the components since the dependencies can be easily mocked or substituted with test doubles.
  3. Configurability: Dependency Injection enables the developer to change the dependencies at runtime by configuring the DI container.
  4. Extensibility: Dependency Injection makes it easier to extend the application by adding new components with their own dependencies.

Dependency Injection finds many real world scenarios or use cases viz.:

  1. Applications with complex dependencies.
  2. Applications with testing requirements.
  3. Applications that are configurable and extensible.
  4. Applications with cross-cutting concerns such as logging, caching, or authentication.

The overuse of Dependency Injection can cause issues such as performance degradation and code complexity.

From the SOLID Design principles, the Dependency Inversion Principle (DIP) promotes Dependency Injection (DI). The DIP states that high-level modules should not depend on low-level modules but instead should depend on abstractions.

In other words, the Dependency Inversion Principle (DIP) advocates the use of abstractions to promote loose coupling and modularity in the code. This way, the high-level modules depend on abstractions, and the concrete implementations of dependencies can be injected through a DI container.

In some cases, it may be better to use simpler techniques such as constructor injection or property injection rather than relying on the DI container.

When making a choice between Constructor Injection and Property Injection, several factors come into play, including:

  1. Required and Optional Dependencies — Use Constructor Injection when the dependencies are required for the proper functioning of the class, and use Property Injection when the dependencies are optional or can have default values.
  2. Number of Dependencies — If the class has a small number of dependencies, use Constructor Injection, and if it has a large number of dependencies, use Property Injection.
  3. Runtime Change in Dependencies — Use Constructor Injection when the dependencies are less likely to change at runtime, and use Property Injection when the dependencies may change at runtime.
  4. Optional and Cyclic Dependencies — Use Constructor Injection when the class does not have optional dependencies, and use Property Injection when the class may have cyclic dependencies that cannot be resolved by Constructor Injection.

In general, using a DI container is recommended when you have a large number of dependencies and need greater configurability and flexibility. A DI container can make it easier to manage dependencies and configure object graphs.

Referring to the code in Repository Pattern for Data Access in Software Development, the below Unit Test code is the refactored version using Dependency Injection.

--

--

Siddharth Phatarphod

Full Stack | Angular| .Net| .Net Core| SQL | Azure PaaS | Azure DevOps | Git | Scrum