eolas/zk/Dependency_injection.md

83 lines
2.1 KiB
Markdown
Raw Normal View History

2023-04-11 20:10:11 +01:00
---
categories:
- Software Engineering
tags: [OOP]
---
# Dependency injection
Dependency injection is an object-oriented design pattern that allows for the
decoupling of dependencies between objects making code more maintainable,
testable and modular.
2023-04-11 20:10:11 +01:00
The basic idea is to resist having any class (C) depend on the specific
implementation details of any other class to which it sustains a dependency (D).
If we can abstract the implementation of D, this makes it easier to swap-out and
change C's dependencies later on without having to re-write C as a result of
changes to D.
2023-04-11 20:10:11 +01:00
This is where interfaces become very helpful because they are schematic
representations of the main methods in a given class (basically their names,
params and return value). As long as this is kept consistent in D when changes
are made, you avoid conflicts when changes or refactorings are made to D.
2023-04-11 20:10:11 +01:00
## Example
In the example to follow we will have two classes:
- `ConsoleLogger`
- This will simply log something and be a dependency for the class below
* `UserService`
- This will depend on `ConsoleLogger`
First we define an interface for the dependency:
```ts
interface ILogger {
log(message: string): void;
}
```
So this is a class that has a single method `log` which receives a `message`
string as an argument and returns a side-effect.
2023-04-11 20:10:11 +01:00
Now we'll implement this class:
```ts
class ConsoleLogger implements ILogger {
log(message: string): void {
console.log(message);
}
}
```
Now we create a class that depends on it:
```ts
class UserService {
private logger: ILogger;
constructor(logger: ILogger) {
this.logger = logger;
}
createUser(username: string): void {
// ... (some logic to create a user)
this.logger.log(`User created: ${username}`);
}
}
```
We can see that the constructor references the `Logger` interface. Thus we
inject the dependency when instantiating `UserService`:
2023-04-11 20:10:11 +01:00
```ts
// First implement our earlier class that matches the `Logger` in its shape:
const logger: ILogger = new ConsoleLogger();
// Then pass it as a dependency:
const userService: UserService = new UserService(logger);
userService.createUser("John Doe");
```