¿Qué es?
El Single Responsibility Principle dice que cada clase debe encargarse de una sola cosa. Si una clase mezcla varias responsabilidades (por ejemplo, lógica de negocio, persistencia y formato de salida), un cambio en cualquiera de esas áreas obliga a tocar la misma clase, aumentando el riesgo de romper algo que no tenía nada que ver.
Antes: varias responsabilidades mezcladas
class Invoice {
constructor(
private items: { name: string; price: number }[],
) {}
getTotal(): number {
return this.items.reduce((sum, item) => sum + item.price, 0);
}
// Responsabilidad extra: formatear la factura
printAsText(): string {
return this.items.map((i) => `${i.name}: ${i.price}`).join('\n');
}
// Responsabilidad extra: persistencia
saveToDatabase(): void {
console.log('Guardando factura en la base de datos...');
}
}Esta clase cambia si cambia el cálculo del total, si cambia el formato de impresión o si cambia la forma de guardar datos. Tres razones distintas para modificarla, tres focos de bugs cruzados.
Después: una responsabilidad por clase
interface InvoiceItem {
name: string;
price: number;
}
class Invoice {
constructor(private items: InvoiceItem[]) {}
getTotal(): number {
return this.items.reduce((sum, item) => sum + item.price, 0);
}
getItems(): InvoiceItem[] {
return this.items;
}
}
class InvoicePrinter {
print(invoice: Invoice): string {
return invoice
.getItems()
.map((i) => `${i.name}: ${i.price}`)
.join('\n');
}
}
class InvoiceRepository {
save(invoice: Invoice): void {
console.log('Guardando factura en la base de datos...', invoice.getTotal());
}
}Ahora Invoice solo modela los datos y el cálculo del total, InvoicePrinter solo sabe formatear, y InvoiceRepository solo sabe persistir. Cada clase cambia por una única razón.