SOLID-Prinzipien in TypeScript: Theorie und Praxis auf fortgeschrittenem Niveau
SOLID – das sind fünf fundamentale Prinzipien der objektorientierten Softwareentwicklung, die es ermöglichen, flexiblen, wartbaren und skalierbaren Code zu erstellen. In TypeScript wird die Umsetzung dieser Prinzipien durch die strenge Typisierung, Schnittstellen und abstrakte Klassen besonders effektiv. In diesem Artikel analysieren wir jedes Prinzip auf fortgeschrittenem Niveau mit realen Beispielen in TypeScript.
1. Single Responsibility Principle (SRP) – Prinzip der einzigen Verantwortung
Theorie: Jede Klasse sollte nur einen einzigen Grund für eine Änderung haben. In TypeScript bedeutet dies, dass ein Modul für genau eine Funktionalität verantwortlich ist.
Fortgeschrittene Praxis: Eine Verletzung des SRP zeigt sich oft in „Gott-Objekten“ (God Objects). Verwenden Sie Komposition und Delegation.
// ❌ Verletzung des SRP: Die Klasse ist für Daten, Validierung und Speicherung verantwortlichclass UserService { constructor(private user: User) {}
validateEmail(email: string): boolean { return /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(email); }
saveToDatabase(): void { // Speicherlogik }
sendWelcomeEmail(): void { // Sende-Logik }}
// ✅ SRP: Verantwortung trenneninterface IEmailValidator { isValid(email: string): boolean;}
interface IUserRepository { save(user: User): Promise<void>;}
interface INotificationService { sendWelcome(user: User): Promise<void>;}
class UserRegistrationService { constructor( private validator: IEmailValidator, private repository: IUserRepository, private notifier: INotificationService ) {}
async register(user: User): Promise<void> { if (!this.validator.isValid(user.email)) { throw new Error('Ungültige E-Mail'); } await this.repository.save(user); await this.notifier.sendWelcome(user); }}2. Open/Closed Principle (OCP) – Prinzip der Offenheit/Geschlossenheit
Theorie: Klassen sollten für Erweiterungen offen, aber für Modifikationen geschlossen sein. In TypeScript wird dies durch abstrakte Klassen und Schnittstellen erreicht.
Fortgeschrittene Praxis: Verwenden Sie das Strategie-Muster (Strategy Pattern) zur Umsetzung des OCP.
// ❌ Verletzung des OCP: Beim Hinzufügen eines neuen Berichtstyps muss die Klasse geändert werdenclass ReportGenerator { generate(data: any[], type: string): string { if (type === 'csv') { return data.map(row => row.join(',')).join(''); } else if (type === 'json') { return JSON.stringify(data); } // Beim Hinzufügen von 'xml' – wird diese Methode modifiziert throw new Error('Nicht unterstütztes Format'); }}
// ✅ OCP: Polymorphismus verwendeninterface IReportFormatter { format(data: any[]): string;}
class CsvFormatter implements IReportFormatter { format(data: any[]): string { return data.map(row => row.join(',')).join(''); }}
class JsonFormatter implements IReportFormatter { format(data: any[]): string { return JSON.stringify(data); }}
class XmlFormatter implements IReportFormatter { format(data: any[]): string { // Implementierung für XML return '<data>...</data>'; }}
class ReportGeneratorOCP { constructor(private formatter: IReportFormatter) {}
generate(data: any[]): string { return this.formatter.format(data); }}
// Verwendung: Erweitern ohne Modifikationconst csvReport = new ReportGeneratorOCP(new CsvFormatter());const jsonReport = new ReportGeneratorOCP(new JsonFormatter());3. Liskov Substitution Principle (LSP) – Prinzip der Substitution von Barbara Liskov
Theorie: Objekte in einem Programm sollten durch Instanzen ihrer Subtypen ersetzbar sein, ohne die Korrektheit des Programms zu beeinträchtigen. In TypeScript ist dies aufgrund der nominativen Typisierung besonders kritisch.