Blog Datasheets Home About me Clients My work Services Contact

G2Labs Grzegorz Grzęda

Using Dependency Injection to adhere to SOLID principles

April 14, 2023

Using Dependency Injection to adhere to SOLID principles

In object-oriented programming, SOLID is a set of principles that when followed, can lead to better, more maintainable and scalable code. One of the key principles of SOLID is the Dependency Inversion Principle (DIP), which states that high-level modules should not depend on low-level modules, but both should depend on abstractions.

One way to adhere to the DIP is by using Dependency Injection (DI). Dependency Injection is a design pattern that allows for the creation and injection of dependencies into a class, rather than the class creating the dependency itself. This results in more flexible and testable code.

In this blog post, we will explore how to use Dependency Injection to adhere to SOLID principles, with extensive examples in C and Python.

Understanding Dependency Injection

Dependency Injection involves injecting the dependencies of a class from the outside. This can be done through constructor injection, setter injection, or interface injection.

Let’s take a look at each of these methods with examples in C and Python.

Constructor Injection

Constructor injection involves passing the dependencies of a class through its constructor.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
// C Example
typedef struct {
    int value;
} Dependency;

typedef struct {
    Dependency* dependency;
} MyClass;

MyClass* MyClass_new(Dependency* dep) {
    MyClass* instance = malloc(sizeof(MyClass));
    instance->dependency = dep;
    return instance;
}
1
2
3
4
5
6
7
8
# Python Example
class Dependency:
    def __init__(self, value):
        self.value = value

class MyClass:
    def __init__(self, dependency):
        self.dependency = dependency

In the above examples, the MyClass constructor takes in a Dependency instance and sets it as a member of the class. This allows the dependency to be injected from the outside, adhering to the DIP.

Setter Injection

Setter injection involves providing setter methods to set the dependencies of a class.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
// C Example
typedef struct {
    int value;
} Dependency;

typedef struct {
    Dependency* dependency;
} MyClass;

void MyClass_setDependency(MyClass* instance, Dependency* dep) {
    instance->dependency = dep;
}
1
2
3
4
5
6
7
8
# Python Example
class Dependency:
    def __init__(self, value):
        self.value = value

class MyClass:
    def set_dependency(self, dependency):
        self.dependency = dependency

In the setter injection examples, the MyClass provides a method to set the Dependency instance, allowing the dependency to be injected after the class has been instantiated.

Interface Injection

Interface injection involves implementing an interface that defines the dependency, and injecting the dependency through that interface.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
// C Example
typedef struct {
    int value;
} Dependency;

typedef struct {
    void (*setDependency)(struct MyClass*, Dependency*);
    Dependency* dependency;
} MyClass;

void MyClass_setDependency(MyClass* instance, Dependency* dep) {
    instance->dependency = dep;
}

MyClass* MyClass_new(void (*setDep)(MyClass*, Dependency*), Dependency* dep) {
    MyClass* instance = malloc(sizeof(MyClass));
    instance->setDependency = setDep;
    instance->setDependency(instance, dep);
    return instance;
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# Python Example
class Dependency:
    def __init__(self, value):
        self.value = value

class MyInterface:
    def set_dependency(self, dependency):
        raise NotImplementedError("Subclasses must implement this method")

class MyClass(MyInterface):
    def set_dependency(self, dependency):
        self.dependency = dependency

In the interface injection examples, we first define an interface that includes a method to set the dependency. We then implement this interface in the MyClass and use it to inject the dependency.

Benefits of Dependency Injection

Using Dependency Injection provides several benefits, including:

By using Dependency Injection, we can adhere to the Dependency Inversion Principle and ultimately the SOLID principles, leading to more maintainable, scalable, and flexible code.

Conclusion

In this blog post, we’ve explored the concept of Dependency Injection and how it can be used to adhere to the SOLID principles, with extensive examples in C and Python. By following the principles of SOLID and using Dependency Injection, we can create code that is more maintainable, testable, and flexible.

I hope this blog post has provided you with a deeper understanding of the benefits of Dependency Injection and how it can contribute to writing better code. Thank you for reading!


➡️ C containers library


⬅️ Simple event handler library


Go back to Posts.