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

234 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