Princípios SOLID em JavaScript: teoria e prática

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Introdução aos princípios SOLID em JavaScript

SOLID é um acrônimo de cinco princípios fundamentais da programação orientada a objetos, formulados por Robert Martin (Uncle Bob). Apesar de JavaScript não ser originalmente uma linguagem OOP estritamente tipada, o JavaScript moderno (ES6+) com classes, módulos e TypeScript utiliza ativamente esses princípios para criar aplicações escaláveis e sustentáveis, especialmente no ambiente Node.js.

Neste artigo, vamos analisar cada um dos cinco princípios SOLID com exemplos práticos de código em JavaScript. Compreender esses princípios ajudará você a escrever código limpo, flexível e resistente a mudanças.



1. Single Responsibility Principle (SRP) — Princípio da Responsabilidade Única

O princípio afirma: uma classe ou módulo deve ter apenas um motivo para ser alterado. Em outras palavras, cada módulo é responsável por uma funcionalidade específica.

Violando o SRP

Considere a classe UserService, que simultaneamente gerencia usuários, envia e-mails e registra ações:

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

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

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

getUsers() { return this.users; }}

Aqui, a classe tem três responsabilidades: gerenciamento de dados, logging e envio de notificações. Alterar a lógica de logging ou envio de e-mail resultará em modificações na classe UserService.

Seguindo o SRP

Vamos separar as responsabilidades em classes distintas:

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; }}

Agora, cada classe é responsável por sua própria tarefa, e alterações em um serviço não afetam os outros.



2. Open-Closed Principle (OCP) — Princípio Aberto/Fechado

O princípio afirma: entidades de software devem estar abertas para extensão, mas fechadas para modificação. Ou seja, devemos ser capazes de adicionar novas funcionalidades sem alterar o código existente.

Violando o OCP

Suponha que temos uma função para calcular a área de formas:

function calculateArea(shape) {  if (shape.type === 'circle') {    return Math.PI * shape.radius ** 2;  } else if (shape.type === 'rectangle') {    return shape.width * shape.height;  }  // Ao adicionar uma nova forma, será necessário modificar esta função}

Seguindo o OCP

Usamos polimorfismo através de classes:

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; }}

// Adicionamos uma nova forma sem modificar o 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