Principios SOLID en Java: teoría y práctica para desarrolladores

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

Principios SOLID en Java: de la teoría al código limpio



Cada desarrollador Java, tarde o temprano, se enfrenta al problema del código "sucio": clases que hacen todo a la vez, dependencias rígidas e imposibilidad de extensión sin romper la lógica existente. Aquí es donde los principios SOLID vienen al rescate: cinco reglas fundamentales de diseño orientado a objetos formuladas por Robert Martin (Tío Bob). En este artículo, analizaremos cada principio en la práctica con ejemplos en Java, para que tu código sea flexible, testeable y fácil de mantener.



1. Single Responsibility Principle (SRP) — Principio de Responsabilidad Única



Esencia: "Una clase debe tener una sola razón para cambiar". En otras palabras, una clase debe encargarse de una tarea claramente definida.



Violación de SRP

Consideremos la clase OrderService, que simultáneamente se encarga del cálculo del precio, el guardado en la base de datos y el envío de email:



public class OrderService {    public void processOrder(Order order) {        // 1. Cálculo del costo        double total = order.getItems().stream()                .mapToDouble(Item::getPrice)                .sum();

// 2. Guardado en BD Database.save(order);

// 3. Envío de notificación EmailService.send("Pedido realizado por un total de: " + total); }}


Problema: Cambiar la lógica de envío de correos o la forma de guardado obligará a modificar OrderService. Esto viola SRP.



Refactorización según SRP

Separamos las responsabilidades en tres clases distintas:



public class PriceCalculator {    public double calculateTotal(Order order) {        return order.getItems().stream()                .mapToDouble(Item::getPrice)                .sum();    }}

public class OrderRepository { public void save(Order order) { Database.save(order); }}

public class NotificationService { public void sendConfirmation(Order order) { EmailService.send("Pedido realizado por un total de: " + order.getTotal()); }}

// Código clientepublic class OrderProcessor { private PriceCalculator calculator; private OrderRepository repository; private NotificationService notifier;

public void processOrder(Order order) { double total = calculator.calculateTotal(order); order.setTotal(total); repository.save(order); notifier.sendConfirmation(order); }}


Resultado: Cada clase tiene una sola razón para cambiar. El código se vuelve modular y testeable.



2. Open-Closed Principle (OCP) — Principio de Abierto/Cerrado



Esencia: "Las entidades de software deben estar abiertas para la extensión, pero cerradas para la modificación". La nueva funcionalidad se añade mediante extensión, no modificando el código existente.



Violación de OCP

Imaginemos un sistema de descuentos donde cada nuevo tipo de descuento requiere modificar el método applyDiscount:



public class DiscountService {    public double applyDiscount(String type, double price) {        if (type.equals("SUMMER")) {            return price * 0.9;        } else if (type.equals("VIP")) {            return price * 0.8;        }        // Añadir un nuevo tipo → modificar la clase        return price;    }}


Solución mediante polimorfismo

Usamos una interfaz y diferentes implementaciones:



public interface Discount {    double apply(double price);}

public class SummerDiscount implements Discount { @Override public double apply(double price) { return price * 0.9; }}

public class VipDiscount implements Discount { @Override public double apply(double price) { return price * 0.8; }}

// Nuevo tipo — simplemente una nueva clas

Blogs

Book Recommendations