Dependency Injection: Besserer Code durch lose Kopplung | Enjyn Gruppe
Hallo Welt
Hallo Welt
Original Lingva Deutsch
Übersetzung wird vorbereitet...
Dieser Vorgang kann bis zu 60 Sekunden dauern.
Diese Seite wird erstmalig übersetzt und dann für alle Besucher gespeichert.
0%
DE Zurück zu Deutsch
Übersetzung durch Lingva Translate

235 Dokumentationen verfügbar

Wissensdatenbank

Dependency Injection Erklaert

Zuletzt aktualisiert: 20.01.2026 um 10:05 Uhr

Dependency Injection: Besserer Code durch lose Kopplung

Dependency Injection macht Code testbar und wartbar. Lernen Sie das Konzept und wie Sie es anwenden.

Das Problem

// ❌ Tight Coupling - schwer zu testen
class OrderService {
    constructor() {
        this.db = new Database();           // Hartcodiert!
        this.mailer = new EmailService();   // Hartcodiert!
        this.logger = new Logger();         // Hartcodiert!
    }

    async createOrder(orderData) {
        const order = await this.db.save(orderData);
        await this.mailer.send(order.userEmail, 'Order confirmed');
        this.logger.info('Order created', order.id);
        return order;
    }
}

// Probleme:
// - Kann nicht mit Mock-DB testen
// - Kann Email-Versand nicht mocken
// - Änderung der DB erfordert Code-Änderung

Die Lösung: Dependency Injection

// ✅ Dependencies werden injiziert
class OrderService {
    constructor(db, mailer, logger) {
        this.db = db;
        this.mailer = mailer;
        this.logger = logger;
    }

    async createOrder(orderData) {
        const order = await this.db.save(orderData);
        await this.mailer.send(order.userEmail, 'Order confirmed');
        this.logger.info('Order created', order.id);
        return order;
    }
}

// Production
const orderService = new OrderService(
    new PostgresDatabase(),
    new SendGridMailer(),
    new WinstonLogger()
);

// Test - mit Mocks!
const orderService = new OrderService(
    mockDatabase,
    mockMailer,
    mockLogger
);

DI-Arten

// 1. Constructor Injection (empfohlen)
class UserService {
    constructor(repository) {
        this.repository = repository;
    }
}

// 2. Setter Injection
class UserService {
    setRepository(repository) {
        this.repository = repository;
    }
}

// 3. Interface Injection
class UserService {
    injectDependencies(container) {
        this.repository = container.get('UserRepository');
    }
}

TypeScript mit Interfaces

// Interfaces definieren den Vertrag
interface IUserRepository {
    findById(id: string): Promise<User | null>;
    save(user: User): Promise<User>;
}

interface IEmailService {
    send(to: string, subject: string, body: string): Promise<void>;
}

// Implementierungen
class PostgresUserRepository implements IUserRepository {
    async findById(id: string) { /* ... */ }
    async save(user: User) { /* ... */ }
}

class MockUserRepository implements IUserRepository {
    users = new Map<string, User>();

    async findById(id: string) {
        return this.users.get(id) || null;
    }
    async save(user: User) {
        this.users.set(user.id, user);
        return user;
    }
}

// Service nutzt Interface
class UserService {
    constructor(
        private repository: IUserRepository,
        private emailService: IEmailService
    ) {}

    async createUser(data: CreateUserDTO) {
        const user = await this.repository.save(new User(data));
        await this.emailService.send(user.email, 'Welcome', '...');
        return user;
    }
}

DI Container (InversifyJS)

npm install inversify reflect-metadata
import { Container, injectable, inject } from 'inversify';
import 'reflect-metadata';

// Symbols für DI
const TYPES = {
    UserRepository: Symbol.for('UserRepository'),
    EmailService: Symbol.for('EmailService'),
    UserService: Symbol.for('UserService'),
};

@injectable()
class PostgresUserRepository implements IUserRepository {
    // ...
}

@injectable()
class UserService {
    constructor(
        @inject(TYPES.UserRepository) private repo: IUserRepository,
        @inject(TYPES.EmailService) private email: IEmailService
    ) {}
}

// Container konfigurieren
const container = new Container();
container.bind<IUserRepository>(TYPES.UserRepository).to(PostgresUserRepository);
container.bind<IEmailService>(TYPES.EmailService).to(SendGridService);
container.bind<UserService>(TYPES.UserService).to(UserService);

// Verwendung
const userService = container.get<UserService>(TYPES.UserService);

PHP: Constructor Injection

<?php
interface UserRepositoryInterface {
    public function find(int $id): ?User;
    public function save(User $user): User;
}

class UserService {
    public function __construct(
        private UserRepositoryInterface $repository,
        private MailerInterface $mailer,
        private LoggerInterface $logger
    ) {}

    public function createUser(array $data): User {
        $user = new User($data);
        $this->repository->save($user);
        $this->mailer->send($user->email, 'Welcome');
        $this->logger->info('User created', ['id' => $user->id]);
        return $user;
    }
}

// Mit Laravel (automatische Injection)
// App\Providers\AppServiceProvider
public function register(): void
{
    $this->app->bind(UserRepositoryInterface::class, EloquentUserRepository::class);
    $this->app->bind(MailerInterface::class, SendGridMailer::class);
}

// Controller - automatisch injiziert
class UserController {
    public function __construct(
        private UserService $userService
    ) {}
}

Testen mit DI

// Jest Test
describe('UserService', () => {
    let userService: UserService;
    let mockRepo: jest.Mocked<IUserRepository>;
    let mockEmail: jest.Mocked<IEmailService>;

    beforeEach(() => {
        mockRepo = {
            findById: jest.fn(),
            save: jest.fn(),
        };
        mockEmail = {
            send: jest.fn(),
        };
        userService = new UserService(mockRepo, mockEmail);
    });

    test('createUser saves and sends email', async () => {
        const userData = { name: 'Max', email: 'max@test.com' };
        mockRepo.save.mockResolvedValue({ id: '1', ...userData });
        mockEmail.send.mockResolvedValue(undefined);

        const result = await userService.createUser(userData);

        expect(mockRepo.save).toHaveBeenCalledWith(expect.any(User));
        expect(mockEmail.send).toHaveBeenCalledWith('max@test.com', 'Welcome', expect.any(String));
        expect(result.id).toBe('1');
    });
});
💡 SOLID Prinzip: DI unterstützt das Dependency Inversion Principle: Abhänge von Abstraktionen (Interfaces), nicht von konkreten Implementierungen.

Weitere Informationen

Enjix Beta

Enjyn AI Agent

Hallo 👋 Ich bin Enjix — wie kann ich dir helfen?
120