El diseño orientado a objetos (OO) es el terreno natural donde los principios SOLID despliegan todo su potencial. Se basa en representar el dominio mediante clases, objetos e interacciones que modelan el comportamiento real, lo que simplifica la comunicación entre el código y las necesidades del negocio.
Comprender por qué el diseño OO es relevante permite justificar el esfuerzo que implica aplicar SOLID y otras prácticas de ingeniería. También aporta un lenguaje común para equipos multidisciplinarios que buscan construir software mantenible.
SOLID surge para resolver problemas recurrentes del diseño OO. Sin objetos bien definidos, los principios pierden sentido; y sin principios, la orientación a objetos se limita a crear clases sin estructura. Esta sinergia se refleja en sistemas donde las responsabilidades están claras, las jerarquías son coherentes y la extensión es segura.
El diseño OO ofrece un vocabulario compartido basado en conceptos del dominio: entidades, servicios, repositorios, controladores. Cuando el código refleja ese lenguaje, las revisiones son más rápidas y las discusiones técnicas se enfocan en la lógica de negocio en lugar de detalles de implementación.
Desde la perspectiva de producto, un diseño OO robusto acelera la incorporación de requerimientos, reduce el tiempo de recuperación frente a fallos y disminuye el costo de capacitación de nuevas personas en el equipo. Cada módulo bien encapsulado se convierte en un activo que la organización puede evolucionar con confianza.
Consideremos un escenario en Java donde se gestiona la asignación de cursos para estudiantes. Un enfoque procedimental tiende a mezclar datos y operaciones en bloques de código difíciles de extender.
class CursoService {
void asignar(String nombreCurso, String nombreAlumno, int cuposRestantes) {
if (cuposRestantes <= 0) {
throw new IllegalArgumentException("No hay cupos disponibles");
}
System.out.println("Asignando " + nombreAlumno + " al curso " + nombreCurso);
// lógica adicional omitida
}
}
En este fragmento, las validaciones, la lógica de negocio y la interacción con la interfaz de usuario se mezclan. Cualquier cambio pequeño obliga a revisar todo el método.
Al modelar el dominio con objetos específicos obtenemos código más expresivo. La asignación del curso se delega en clases que representan conceptos concretos.
class Curso {
private final String nombre;
private int cuposRestantes;
Curso(String nombre, int cuposRestantes) {
this.nombre = nombre;
this.cuposRestantes = cuposRestantes;
}
void inscribir(Alumno alumno) {
if (cuposRestantes <= 0) {
throw new IllegalStateException("Cupos agotados en " + nombre);
}
cuposRestantes--;
alumno.notificarInscripcion(nombre);
}
}
class Alumno {
private final String nombre;
Alumno(String nombre) {
this.nombre = nombre;
}
void notificarInscripcion(String curso) {
System.out.println(nombre + " inscripto en " + curso);
}
}
Ahora el servicio que coordina la operación se mantiene delgado y utiliza clases que encapsulan sus responsabilidades.
class AsignadorDeCursos {
void asignar(Curso curso, Alumno alumno) {
curso.inscribir(alumno);
}
}
Este rediseño sienta las bases para aplicar SRP y LSP en etapas posteriores, además de permitir nuevas reglas (listas de espera, notificaciones externas) sin reescribir el código existente.
Un diseño orientado a objetos sólido no surge por accidente: requiere intención, disciplina y aprendizaje constante. En los siguientes capítulos exploraremos cómo cada principio SOLID refuerza estas ideas con reglas concretas.