Regel
Klassen sollten eine einzige Verantwortung haben.
Klassen, die mehrere Belange behandeln, verletzen
das Single Responsibility Principle.
Unterstützte Sprachen: JS, TS, PY, JAVA, C/C++,
C#, Swift/Objective C, Ruby. PHP, Kotlin,
Scala, Rust, Haskell, Groovy, Dart. Julia,
Elixit, Klojure, OCaml, DelphiEinleitung
Klassen, die zu viel tun, werden zu Engpässen. Eine Klasse, die Authentifizierung, E-Mails und Validierung handhabt, erfordert Änderungen, sobald sich ein Aspekt weiterentwickelt, was das Risiko von Brüchen in nicht verwandter Funktionalität birgt. Tests erfordern das Mocken der gesamten Klasse, selbst wenn nur ein Aspekt getestet wird. Das Single Responsibility Principle besagt, dass eine Klasse nur einen Grund zur Änderung haben sollte.
Warum es wichtig ist
Code-Wartbarkeit: Klassen mit mehreren Verantwortlichkeiten ändern sich häufiger, da die Entwicklung eines Anliegens die gesamte Klasse betrifft.
Testkomplexität: Das Testen von Klassen mit mehreren Verantwortlichkeiten erfordert das Mocking aller Abhängigkeiten, selbst wenn nur eine Funktion getestet wird.
Wiederverwendbarkeit: Man kann eine Verantwortung nicht extrahieren, ohne alle Abhängigkeiten mitzubringen. Entwickelnde duplizieren Code, anstatt Klassen mit mehreren Verantwortlichkeiten zu entwirren.
Teamkoordination: Mehrere Entwickelnde, die an derselben Klasse für verschiedene Features arbeiten, erzeugen häufig Merge-Konflikte. Klassen mit einfacher Verantwortlichkeit ermöglichen parallele Entwicklung ohne Konflikte.
Code-Beispiele
❌ Nicht konform:
class UserManager {
async createUser(userData) {
const user = await db.users.insert(userData);
await this.sendWelcomeEmail(user.email);
await this.logEvent('user_created', user.id);
await cache.set(`user:${user.id}`, user);
return user;
}
async sendWelcomeEmail(email) {
const template = this.loadEmailTemplate('welcome');
await emailService.send(email, template);
}
async logEvent(event, userId) {
await analytics.track(event, { userId, timestamp: Date.now() });
}
}
Warum es falsch ist: Diese Klasse verarbeitet Datenbankoperationen, E-Mail-Versand, Protokollierung und Caching. Änderungen an E-Mail-Vorlagen, Protokollformaten oder der Cache-Strategie erfordern alle eine Modifikation dieser Klasse. Das Testen der Benutzererstellung bedeutet das Mocken von E-Mail-Diensten, Analysen und Cache, was Tests langsam und anfällig macht.
✅ Konform:
class UserRepository {
async create(userData) {
return await db.users.insert(userData);
}
}
class EmailNotificationService {
async sendWelcomeEmail(email) {
const template = await this.templateLoader.load('welcome');
return await this.emailSender.send(email, template);
}
}
class UserEventLogger {
async logCreation(userId) {
return await this.analytics.track('user_created', {
userId,
timestamp: Date.now()
});
}
}
class UserService {
constructor(repository, emailService, eventLogger, cache) {
this.repository = repository;
this.emailService = emailService;
this.eventLogger = eventLogger;
this.cache = cache;
}
async createUser(userData) {
const user = await this.repository.create(userData);
await Promise.all([
this.emailService.sendWelcomeEmail(user.email),
this.eventLogger.logCreation(user.id),
this.cache.set(`user:${user.id}`, user)
]);
return user;
}
}
Warum dies wichtig ist: Jede Klasse hat eine klare Verantwortung: Datenpersistenz, E-Mail-Versand, Event-Logging oder Orchestrierung. Änderungen an E-Mail-Vorlagen betreffen nur EmailNotificationService. Beim Testen der Benutzererstellung können einfache Stubs für Abhängigkeiten verwendet werden. Klassen können unabhängig voneinander über verschiedene Funktionen hinweg wiederverwendet werden.
Fazit
Das Single Responsibility Principle (Prinzip der einzigen Verantwortung) geht nicht darum, Klassen so klein wie möglich zu machen, sondern sicherzustellen, dass jede Klasse einen klaren Grund zur Änderung hat. Wenn eine Klasse beginnt, mehrere Belange zu behandeln, refaktorieren Sie, indem Sie jede Verantwortung in eine eigene Klasse mit einer fokussierten Schnittstelle extrahieren. Dies erleichtert das Testen, Warten und Weiterentwickeln von Code, ohne kaskadierende Änderungen über nicht verwandte Funktionalitäten hinweg zu verursachen.
.avif)
