Principios SOLID en JavaScript: teoría y práctica

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

Introducción a los principios SOLID en JavaScript

SOLID es un acrónimo de cinco principios fundamentales de la programación orientada a objetos, formulados por Robert Martin (Tío Bob). A pesar de que JavaScript no fue originalmente un lenguaje OOP estrictamente tipado, el JavaScript moderno (ES6+) con clases, módulos y TypeScript utiliza activamente estos principios para crear aplicaciones escalables y mantenibles, especialmente en el entorno Node.js.

En este artículo analizaremos cada uno de los cinco principios SOLID con ejemplos prácticos de código en JavaScript. Comprender estos principios le ayudará a escribir código limpio, flexible y resistente a los cambios.



1. Single Responsibility Principle (SRP) — Principio de responsabilidad única

El principio establece: una clase o módulo debe tener solo una razón para cambiar. En otras palabras, cada módulo es responsable de una funcionalidad específica.

Violación del SRP

Consideremos la clase UserService, que simultáneamente gestiona usuarios, envía correos electrónicos y registra acciones:

class UserService {  constructor() {    this.users = [];  }

addUser(name) { this.users.push({ name }); console.log('User added'); // Logging this.sendEmail(name); // Envío de email }

sendEmail(name) { console.log(`Email sent to ${name}`); }

getUsers() { return this.users; }}

Aquí la clase tiene tres responsabilidades: gestión de datos, registro y envío de notificaciones. Un cambio en la lógica de registro o envío de correos electrónicos implicaría modificar la clase UserService.

Cumplimiento del SRP

Dividamos las responsabilidades en clases separadas:

class Logger {  log(message) {    console.log(`[LOG]: ${message}`);  }}

class EmailService { send(name) { console.log(`Email sent to ${name}`); }}

class UserService { constructor(logger, emailService) { this.users = []; this.logger = logger; this.emailService = emailService; }

addUser(name) { this.users.push({ name }); this.logger.log(`User ${name} added`); this.emailService.send(name); }

getUsers() { return this.users; }}

Ahora cada clase se encarga de su propia tarea, y los cambios en un servicio no afectan a los demás.



2. Open-Closed Principle (OCP) — Principio de abierto/cerrado

El principio establece: las entidades de software deben estar abiertas para extensión, pero cerradas para modificación. Es decir, debemos poder agregar nueva funcionalidad sin modificar el código existente.

Violación del OCP

Supongamos que tenemos una función para calcular el área de figuras:

function calculateArea(shape) {  if (shape.type === 'circle') {    return Math.PI * shape.radius ** 2;  } else if (shape.type === 'rectangle') {    return shape.width * shape.height;  }  // Al agregar una nueva figura, habría que modificar esta función}

Cumplimiento del OCP

Usamos polimorfismo a través de clases:

class Shape {  area() {    throw new Error('Method "area()" must be implemented');  }}

class Circle extends Shape { constructor(radius) { super(); this.radius = radius; } area() { return Math.PI * this.radius ** 2; }}

class Rectangle extends Shape { constructor(width, height) { super(); this.width = width; this.height = height; } area() { return this.width * this.height; }}

// Agregamos una nueva figura sin modificar el código existenteclass Triangle extends Shape { constructor(base, height) { super(); this.base = base; this.height = height; } area() { return (this.base * this.height) / 2; }}

function calculateArea

Blogs

Book Recommendations