Al cerrar el módulo 2 hiciste un diagnóstico incómodo de tu propio programa: mayorRetraso, empleadoMayorRetraso y libroMayorRetraso son tres variables sueltas que describen una sola cosa, y nada impide actualizar una y olvidar las otras dos. Ese diagnóstico no es un detalle de estilo: es el síntoma de un límite estructural del estilo de programación que has usado hasta ahora. Un programa procedimental organiza el código en pasos; cuando los pasos crecen, los datos relacionados se dispersan por variables independientes y nadie garantiza que sigan siendo coherentes entre sí. La programación orientada a objetos (POO) propone otra organización: agrupar los datos con las operaciones que los gobiernan, en unidades llamadas objetos, de modo que un dato incoherente sea imposible de construir. Esta lección no escribe todavía la clase Libro —eso llega en la siguiente—; su trabajo es que entiendas qué problema resuelve la POO, con qué vocabulario se piensa y cómo se modela el dominio de BiblioTech antes de teclear una sola llave.
Contenido
- El punto de partida:
BiblioTechApp2.0 vista de cerca - Por qué el código procedimental se degrada al crecer
- Qué es la orientación a objetos
- Clase frente a objeto: el plano y la casa
- Identidad, estado y comportamiento
- Instancia y referencia
- Los cuatro pilares en un vistazo
- Modelar el dominio: de los sustantivos a las clases
- El modelo objetivo de BiblioTech
- Relaciones entre clases: asociación, composición y agregación
- Ventajas reales de la POO... y sus costes
- Errores Comunes y Consejos
- Ejercicios
- El punto de partida:
BiblioTechApp 2.0 vista de cerca
BiblioTechApp 2.0 vista de cercaTu aplicación funciona. Muestra un menú, valida entradas, aplica las reglas de negocio de Nexus Software y emite recibos alineados. Pero mira el bloque de declaraciones con el que arranca main:
// Reglas de negocio
final int DIAS_PRESTAMO = 15;
final double TARIFA_DIARIA = 0.25;
final double MULTA_MAXIMA = 20.0;
final int UMBRAL_LEVE = 7;
// Datos de la operacion en curso
String empleado;
String titulo;
String isbn;
int diasTranscurridos;
int diasRetraso;
double multa;
String estado;
String gravedad;
// Estadisticas de sesion
int devoluciones = 0;
int prestamos = 0;
double recaudacion = 0.0;
int mayorRetraso = 0;
String empleadoMayorRetraso = "-";
String libroMayorRetraso = "-";Cuenta lo que hay ahí: veinte variables en el mismo ámbito, todas visibles desde cualquier punto de las doscientas líneas de main, todas modificables desde cualquier punto, y ninguna relación explícita entre ellas. El compilador no sabe que titulo e isbn describen el mismo libro. No sabe que mayorRetraso y empleadoMayorRetraso deben cambiar a la vez. No sabe que multa nunca puede superar MULTA_MAXIMA. Todo eso vive en tu cabeza y en los comentarios.
- Por qué el código procedimental se degrada al crecer
El estilo procedimental —datos por un lado, pasos por otro— funciona perfectamente en programas pequeños. El problema aparece cuando el programa crece, y se manifiesta siempre de las mismas cuatro formas:
| Síntoma | Cómo se ve en BiblioTech | Consecuencia |
|---|---|---|
| Dispersión de datos | titulo, isbn, autor describen un libro pero son variables independientes |
Nada garantiza que el ISBN corresponda al título |
| Estado global mutable | Las veinte variables son visibles en todo main |
Cualquier línea puede corromper cualquier dato |
| Reglas duplicadas | El tope de multa se aplica en la rama de devolución y en la tabla de escala | Si cambia la regla, hay que buscar todas las copias |
| Escalado imposible | Para dos libros harían falta titulo1, isbn1, titulo2, isbn2... |
El código crece linealmente con los datos |
El cuarto síntoma es el más revelador. Pregúntate cómo registrarías dos devoluciones simultáneas con el diseño actual. La respuesta honesta es: duplicando variables. Y con tres, triplicándolas. Ese camino no lleva a ninguna parte.
flowchart LR
subgraph PROC["Procedimental"]
D1["titulo"]
D2["isbn"]
D3["diasRetraso"]
D4["multa"]
F1["calcular"]
F2["imprimir"]
F1 -.-> D1
F1 -.-> D3
F2 -.-> D2
F2 -.-> D4
end
subgraph OO["Orientado a objetos"]
O1["Libro
titulo, isbn
estaDisponible()"]
O2["Prestamo
diasRetraso, multa
calcularMulta()"]
O2 --> O1
end
A la izquierda, datos y funciones se cruzan en todas direcciones. A la derecha, cada dato vive dentro de la unidad que sabe qué hacer con él.
- Qué es la orientación a objetos
La POO es un paradigma: una manera de organizar un programa. Su idea central cabe en una frase:
Un programa es un conjunto de objetos que colaboran enviándose mensajes; cada objeto guarda sus propios datos y es el único responsable de las operaciones que los modifican.
Tres consecuencias inmediatas:
- Los datos dejan de ser pasivos. Un
Prestamono es una tupla de valores que alguien inspecciona desde fuera; es una entidad a la que le preguntas cuánta multa corresponde. - Las reglas viven junto a los datos que gobiernan. La regla "la multa nunca supera 20 €" pasa a ser un asunto interno de
Prestamo, no una línea perdida enmain. - El programa se lee en el vocabulario del negocio.
prestamo.calcularMulta()se entiende sin conocer la implementación;multa = diasRetraso * TARIFA_DIARIA; if (multa >= MULTA_MAXIMA) multa = MULTA_MAXIMA;obliga a leer aritmética para deducir la intención.
Java es un lenguaje orientado a objetos por diseño: salvo los ocho tipos primitivos que viste en el módulo 1, todo lo que has manipulado ya era un objeto. String, Scanner o System.out son objetos; scanner.nextLine() es exactamente un mensaje enviado a un objeto. Llevas dos módulos usando POO sin saberlo; lo que empieza ahora es escribir tus propios tipos.
- Clase frente a objeto: el plano y la casa
Esta es la distinción fundamental, y conviene fijarla con una analogía antes de ver sintaxis.
Una clase es un plano de arquitecto: describe qué tendrá cada casa (número de habitaciones, superficie) y qué se podrá hacer con ella (abrir la puerta, encender la luz). El plano no es una casa: no puedes vivir en él, no tiene dirección postal y no se puede pintar de azul.
Un objeto es una casa construida a partir de ese plano: ocupa un lugar concreto, tiene valores concretos (140 m², pintada de azul) y se puede usar. Del mismo plano se construyen mil casas, todas con la misma estructura y cada una con sus propios valores.
| Concepto | Clase | Objeto |
|---|---|---|
| Naturaleza | Plantilla, definición, tipo | Ejemplar concreto en memoria |
| Cuándo existe | En tiempo de compilación (es código) | En tiempo de ejecución (ocupa memoria) |
| Cuántos hay | Uno por definición | Tantos como se creen |
| En BiblioTech | Libro |
"Java Efectivo", "Refactorización" |
| Analogía | El plano, el molde, la receta | La casa, la pieza, el pastel |
Traducido al dominio: escribirás una clase Libro y crearás con ella tres objetos, uno para "Java Efectivo" (ISBN 978-0000000001), otro para "Patrones de Diseño" (978-0000000002) y otro para "Refactorización" (978-0000000003). Los tres comparten estructura —todos tienen título, autor, ISBN, año y disponibilidad— y difieren en los valores.
- Identidad, estado y comportamiento
Todo objeto se describe con tres propiedades. Interiorizarlas te ahorrará confusiones durante todo el módulo.
- Identidad: qué objeto es, con independencia de sus valores. Dos ejemplares físicos de "Java Efectivo" en la estantería son objetos distintos aunque compartan título e ISBN. En Java la identidad es la posición en memoria, y es lo que compara
==(lo viste en el módulo 1 con el string pool, y volverá en 03-09). - Estado: los valores que el objeto guarda en un instante. El estado de un
Libroincluyetitulo,autor,isbn,anioPublicacionydisponible. El estado cambia:disponiblepasa detrueafalsecuando alguien se lo lleva. - Comportamiento: las operaciones que el objeto sabe realizar. Un
Prestamosabe calcular sus días de retraso, su multa y su gravedad.
Aplicado al vocabulario que ya usas:
| Clase | Estado (atributos) | Comportamiento (operaciones) |
|---|---|---|
Libro |
titulo, autor, isbn, anioPublicacion, disponible |
prestarse, devolverse, decir si está disponible |
Empleado |
nombre, identificador, préstamos acumulados |
registrar un préstamo, decir cuántos acumula |
Prestamo |
libro, empleado, diasTranscurridos |
calcular diasRetraso, multa, gravedad, estado |
Fíjate en un detalle que gobernará todo el módulo: la columna de la derecha es lo que hoy está suelto en main. La POO no inventa comportamiento nuevo; lo muda de sitio, del procedimiento al objeto que le corresponde.
- Instancia y referencia
Dos palabras que oirás constantemente y que conviene separar desde ya:
- Instancia es sinónimo de objeto: el ejemplar concreto creado a partir de una clase. "Crear una instancia de
Libro" y "crear un objetoLibro" significan lo mismo. - Referencia es la variable con la que llegas a ese objeto. No es el objeto: es la dirección donde vive.
La distinción importa porque en Java nunca manipulas objetos directamente, siempre a través de referencias. Cuando escribes:
ocurren tres cosas independientes: se reserva memoria para un objeto Libro en el heap (lo llamábamos "montículo" en el módulo 1), se declara una variable javaEfectivo en la pila, y se guarda en esa variable la dirección del objeto. Una consecuencia inmediata, que la lección 03-02 desarrolla con detalle: dos referencias pueden apuntar al mismo objeto, y entonces un cambio hecho a través de una se ve a través de la otra.
- Los cuatro pilares en un vistazo
La POO se sostiene sobre cuatro ideas. Aquí las tienes en una frase cada una, con la lección donde se desarrollan; no intentes dominarlas ahora, solo reconocer los nombres cuando aparezcan.
| Pilar | En una frase | Ejemplo en BiblioTech | Lección |
|---|---|---|---|
| Encapsulamiento | El objeto oculta su representación interna y solo expone operaciones controladas | Nadie puede asignar una multa arbitraria: se calcula al devolver | 03-07 |
| Herencia | Una clase puede definirse como una especialización de otra y reutilizar lo que esta ya define | Libro, Revista y Dvd son tipos de Material prestable |
03-05 |
| Polimorfismo | Una misma llamada produce comportamientos distintos según el tipo real del objeto | material.calcularMulta() cobra 0,25 €/día si es libro y 0,50 €/día si es DVD |
03-06 |
| Abstracción | Se modela solo lo esencial para el problema y se oculta el resto | A BiblioTech le importa el ISBN de un libro, no su peso ni su color de portada | 03-08 |
Un apunte de honestidad: estos cuatro términos se recitan mucho y se entienden poco. Al final del módulo no los habrás memorizado, los habrás usado, que es la única forma de aprenderlos.
- Modelar el dominio: de los sustantivos a las clases
Antes de escribir código hay que decidir qué clases existen. Existe una técnica sencilla y sorprendentemente eficaz para empezar: subrayar los sustantivos del enunciado del problema. Este es el enunciado de BiblioTech tal como lo daría el departamento de Nexus Software:
La biblioteca técnica interna gestiona los libros que los empleados toman en préstamo. Cada libro tiene título, autor, ISBN y año de publicación, y puede estar disponible o no. Un préstamo dura 15 días; pasado ese plazo se acumulan días de retraso que generan una multa de 0,25 € diarios con un máximo de 20 €. Un retraso de hasta 7 días se considera leve; por encima, grave.
Sustantivos candidatos: biblioteca, libro, empleado, préstamo, título, autor, ISBN, año, días, multa, retraso.
Ahora se filtran con tres criterios:
- ¿Tiene identidad propia y estado que cambia? → es candidato a clase. Libro, Empleado, Préstamo lo cumplen.
- ¿Es un simple valor descriptivo de otra cosa? → es candidato a atributo. Título, ISBN, año describen un libro; días de retraso y multa describen un préstamo.
- ¿Es el sistema entero o un concepto vago? → normalmente no es una clase de dominio. Biblioteca es el sistema; lo que aparecerá más adelante es un
Catalogoque guarda materiales y unGestorPrestamosque orquesta operaciones (módulos 5 y siguientes).
Resultado del filtrado para este módulo: tres clases, Libro, Empleado y Prestamo, exactamente las que se anunciaron al cerrar el módulo 2.
Y una pregunta que separa un modelo bueno de uno mediocre: ¿de quién es cada responsabilidad? Una responsabilidad mal colocada compila igual, pero envenena el diseño.
| Responsabilidad | ¿De quién? | Por qué |
|---|---|---|
| Saber su ISBN | Libro |
Es un dato intrínseco del libro |
| Saber si está prestado | Libro |
Es un estado del ejemplar |
| Calcular los días de retraso | Prestamo |
Depende del plazo y del tiempo transcurrido, no del libro |
| Calcular la multa | Prestamo |
Es una consecuencia del retraso de esa operación |
| Saber cuántos préstamos acumula | Empleado |
Es historial de la persona |
| Imprimir el recibo | Ni Libro ni Prestamo |
Es presentación; se separa del dominio (lección 03-08) |
- El modelo objetivo de BiblioTech
Este es el modelo al que llegarás al terminar el módulo. Guárdalo como mapa: cada lección añade una pieza.
classDiagram
class Libro {
-String titulo
-String autor
-String isbn
-int anioPublicacion
-boolean disponible
+estaDisponible() boolean
+prestar() void
+devolver() void
+toString() String
+equals(Object) boolean
}
class Empleado {
-String nombre
-String identificador
-int prestamosAcumulados
+registrarPrestamo() void
+getPrestamosAcumulados() int
+toString() String
}
class Prestamo {
-Libro libro
-Empleado empleado
-int diaPrestamo
-int diaVencimiento
-int diasTranscurridos
+calcularDiasRetraso() int
+calcularMulta() double
+clasificarGravedad() String
+registrarDevolucion(int) void
+toString() String
}
Prestamo --> Libro : libro prestado
Prestamo --> Empleado : solicitante
Léelo así: un Prestamo conoce un Libro y un Empleado; ni el libro ni el empleado necesitan conocer el préstamo. Las flechas indican la dirección de la dependencia, y esa dirección es una decisión de diseño, no un accidente.
En la lección 03-05 este diagrama crecerá hacia arriba: aparecerá una clase Material de la que Libro, Revista y Dvd serán especializaciones.
- Relaciones entre clases: asociación, composición y agregación
Las clases rara vez viven aisladas. Hay tres formas típicas de relacionarse, además de la herencia:
| Relación | Significado | Duración del vínculo | Ejemplo en BiblioTech |
|---|---|---|---|
| Asociación | "usa" o "conoce a" | Independiente | Prestamo conoce al Empleado que lo solicita |
| Agregación | "tiene un" con partes que sobreviven al todo | El todo puede desaparecer y las partes siguen | Un Catalogo agrega Libros: si se borra el catálogo, los libros existen igual |
| Composición | "está formado por" con partes que mueren con el todo | Las partes no tienen sentido sin el todo | Un Prestamo compone su propio registro de fechas y estado |
| Herencia | "es un" | Estructural, en tiempo de compilación | Un Libro es un Material (lección 03-05) |
La prueba práctica para distinguir agregación de composición es preguntarse: si destruyo el objeto contenedor, ¿tiene sentido que la parte siga existiendo? Si la respuesta es sí, es agregación; si es no, composición. Un libro sobrevive al catálogo que lo lista; el desglose interno de una multa no sobrevive al préstamo que la generó.
No te obsesiones con estas etiquetas: en código Java, asociación, agregación y composición se escriben casi igual (un campo que referencia a otro objeto). Su valor está en el diseño y en la conversación con otros desarrolladores.
- Ventajas reales de la POO... y sus costes
Los cursos suelen enumerar solo la columna izquierda. Un profesional necesita las dos.
| Ventajas | Costes |
|---|---|
| Los datos relacionados viajan juntos y no se descoordinan | Indirección: para saber qué hace prestamo.calcularMulta() hay que abrir otro fichero |
| Las reglas de negocio están en un único lugar | Ceremonia: más ficheros, más líneas para lo mismo en programas pequeños |
| El código se lee en el vocabulario del negocio | Sobrediseño: es fácil crear jerarquías de siete niveles para un problema de dos |
| Añadir un tipo nuevo no obliga a tocar el código existente (03-06) | Curva de aprendizaje: herencia y polimorfismo tienen trampas sutiles |
| Cada clase se puede probar por separado (módulo 11) | Acoplamiento oculto: una clase base mal diseñada rompe a todas sus hijas (03-05) |
Regla práctica que te servirá durante años: la POO paga cuando el programa tiene que crecer y cambiar. Un script de treinta líneas que se ejecuta una vez no necesita clases. BiblioTech sí: va a crecer durante diez módulos más.
Errores Comunes y Consejos
- Confundir clase con objeto al hablar. "Voy a modificar el libro" es ambiguo: ¿la clase
Libro(el plano, y afecta a todos) o el objetojavaEfectivo(un ejemplar)? Acostúmbrate a nombrar la clase en mayúscula y singular (Libro) y los objetos con nombres concretos (javaEfectivo). - Convertir en clase todo sustantivo del enunciado. No todo lo nombrable merece una clase.
tituloes unString, no una claseTitulo. Aplica el filtro del apartado 8: identidad + estado que cambia. - Crear clases que solo guardan datos. Una clase con cinco campos y diez getters, sin ningún comportamiento, es una estructura de datos disfrazada (se le llama modelo anémico). Pregúntate siempre qué sabe hacer la clase, no solo qué contiene.
- Colocar el comportamiento en la clase equivocada. Si
Librocalculase multas, tendría que conocer plazos, tarifas y días transcurridos, datos que no le pertenecen. Cada operación va donde están los datos que necesita. - Empezar por la herencia. Es el pilar más llamativo y el más peligroso. Modela primero clases planas que funcionen; la jerarquía aparecerá sola cuando la necesites (lección 03-05).
- Consejo: dibuja antes de teclear. Cinco minutos de diagrama de clases en papel ahorran horas de refactorización. No necesitas UML formal: cajas con nombre, atributos y flechas bastan.
- Consejo: nombra en el idioma del negocio.
Prestamo,LibroyEmpleadoson mejores nombres queDataRecord,ItemoManager, porque cualquiera de Nexus Software los entiende sin explicación.
Ejercicios
Ejercicio 1: identificar clases, atributos y responsabilidades
Nexus Software quiere ampliar BiblioTech con un módulo de salas de reuniones:
Los empleados reservan salas de reuniones. Cada sala tiene un nombre, una capacidad máxima de personas y un equipamiento (proyector sí o no). Una reserva la hace un empleado para una sala, en una franja horaria concreta, con un número de asistentes que no puede superar la capacidad de la sala. Una reserva puede cancelarse.
Sin escribir código Java completo:
- Enumera los sustantivos y clasifícalos en clase, atributo o descartado, justificando cada decisión.
- Escribe una tabla de responsabilidades: qué debe saber hacer cada clase.
- Indica qué tipo de relación (asociación, agregación o composición) hay entre
ReservaySala, y entreReservayEmpleado.
Ejercicio 2: diagrama y esqueletos de clase
Con el resultado del ejercicio 1:
- Dibuja el diagrama
classDiagramde mermaid del modelo de salas. - Escribe los esqueletos de las clases (solo la declaración y los campos, con comentarios donde irían las operaciones). No implementes nada: la sintaxis completa llega en 03-02.
Ejercicio 3: detectar responsabilidades mal colocadas
Un compañero propone este diseño para BiblioTech. Señala tres decisiones que consideres erróneas y explica dónde debería vivir cada responsabilidad:
class Libro {
String titulo;
String isbn;
double multaDelUltimoPrestamo; // (a)
String nombreDelEmpleadoActual; // (b)
void imprimirReciboDeDevolucion() { } // (c)
void guardarEnFichero() { } // (d)
}Soluciones
Solución 1
1. Clasificación de sustantivos
| Sustantivo | Clasificación | Justificación |
|---|---|---|
| Empleado | Clase | Ya existe en el modelo; tiene identidad y estado propio |
| Sala | Clase | Tiene identidad (cada sala es distinta) y estado (equipamiento, capacidad) |
| Reserva | Clase | Tiene identidad, estado que cambia (activa/cancelada) y comportamiento (cancelarse) |
| Nombre, capacidad, proyector | Atributos de Sala |
Son valores que describen la sala, no entidades con vida propia |
| Franja horaria, asistentes | Atributos de Reserva |
Describen una reserva concreta |
| Módulo, sistema | Descartados | Son el programa entero, no conceptos del dominio |
Un matiz profesional: franja horaria podría llegar a ser una clase propia (Franja, con hora de inicio y fin, y capaz de decir si se solapa con otra). Es una decisión legítima, pero prematura ahora: empieza por atributos y promueve a clase solo cuando el concepto acumule comportamiento propio.
2. Responsabilidades
| Clase | Debe saber |
|---|---|
Sala |
Su nombre, su capacidad y si tiene proyector; decir si admite un número de asistentes |
Empleado |
Su nombre e identificador; cuántas reservas acumula |
Reserva |
Qué sala, qué empleado, qué franja y cuántos asistentes; validar que caben; cancelarse; decir si está activa |
Observa que "decir si admite N asistentes" es de Sala, porque la capacidad es un dato suyo; en cambio "validar que caben" es de Reserva, porque solo la reserva conoce el número de asistentes. Cada una aporta lo que sabe.
3. Relaciones
Reserva→Sala: asociación (o agregación). La sala existe antes y después de la reserva; cancelar una reserva no destruye la sala.Reserva→Empleado: asociación. El empleado tiene vida propia en la empresa.
No hay composición evidente en este modelo, salvo que la franja horaria se modelase como objeto interno de la reserva: entonces sí sería composición, porque esa franja no significa nada fuera de su reserva.
Solución 2
Diagrama
classDiagram
class Sala {
-String nombre
-int capacidadMaxima
-boolean tieneProyector
+admite(int asistentes) boolean
}
class Empleado {
-String nombre
-String identificador
-int reservasAcumuladas
}
class Reserva {
-Sala sala
-Empleado solicitante
-int horaInicio
-int horaFin
-int asistentes
-boolean activa
+cancelar() void
+estaActiva() boolean
}
Reserva --> Sala : reserva
Reserva --> Empleado : solicitada por
Esqueletos
package com.nexussoftware.bibliotech.dominio;
public class Sala {
String nombre;
int capacidadMaxima;
boolean tieneProyector;
// Operaciones previstas:
// admite(int asistentes) -> boolean
}package com.nexussoftware.bibliotech.dominio;
public class Reserva {
Sala sala; // referencia a otro objeto: asociacion
Empleado solicitante; // asociacion
int horaInicio; // 9 = 09:00, formato entero provisional
int horaFin;
int asistentes;
boolean activa;
// Operaciones previstas:
// cancelar() -> void
// estaActiva() -> boolean
// cabenTodos() -> boolean (delega en sala.admite(asistentes))
}Dos detalles que reaparecerán: los campos que referencian a otras clases (Sala sala) son exactamente lo que dibujábamos como flecha en el diagrama, y las horas se modelan como enteros porque LocalTime pertenece a java.time, que se estudia en la lección 10-05.
Solución 3
(a) multaDelUltimoPrestamo en Libro está mal colocado. La multa es consecuencia de una operación de préstamo concreta, no una propiedad del libro. Con este diseño, si el mismo ejemplar se presta cinco veces, el campo solo recuerda la última multa y pierde el historial; y peor aún, obliga a Libro a conocer plazos y tarifas, que no son asunto suyo. La multa pertenece a Prestamo.
(b) nombreDelEmpleadoActual en Libro está mal por dos razones. Primera, es la misma dispersión que sufre hoy BiblioTechApp: guardar el nombre en lugar del Empleado deja el dato huérfano y sin posibilidad de acceder al identificador o a los préstamos acumulados. Segunda, y más importante, el vínculo libro–empleado solo existe mientras hay un préstamo, así que su lugar natural es la clase Prestamo, que ya relaciona ambos. Si Libro debe saber algo, es únicamente si está disponible o no.
(c) imprimirReciboDeDevolucion() mezcla dominio y presentación. Una clase de dominio no debería saber que existe una consola, ni el formato del recibo, ni el ancho de las columnas. Si mañana BiblioTech se convierte en aplicación web (módulo 12), habría que reescribir la clase entera. El recibo lo genera quien se ocupa de la interfaz. Es el problema de los niveles de abstracción mezclados, que se trata a fondo en la lección 03-08.
(d) guardarEnFichero() añade una responsabilidad ajena. Persistir en disco es un asunto de infraestructura (módulo 7), no del concepto "libro". Una clase con dos motivos distintos para cambiar —cambia el negocio, cambia el formato de fichero— es una clase que hará infelices a quienes la mantengan.
Diseño corregido, en esqueleto:
public class Libro {
String titulo;
String autor;
String isbn;
int anioPublicacion;
boolean disponible;
// Operaciones: estaDisponible(), prestar(), devolver()
}
public class Prestamo {
Libro libro; // que se presta
Empleado empleado; // a quien se presta
int diasTranscurridos;
// Operaciones: calcularDiasRetraso(), calcularMulta(), clasificarGravedad()
}Conclusión
En esta lección has cambiado de forma de pensar antes de cambiar de forma de escribir. Has visto por qué el estilo procedimental se degrada cuando el programa crece —datos dispersos, estado global, reglas duplicadas, imposibilidad de escalar—, con tu propio BiblioTechApp como caso de estudio. Has aprendido el vocabulario esencial: clase como plano y objeto como ejemplar, identidad, estado y comportamiento, instancia y referencia. Tienes un mapa de los cuatro pilares y de la lección en la que se desarrolla cada uno. Y, sobre todo, has modelado el dominio de BiblioTech: de los sustantivos del enunciado a tres clases —Libro, Empleado, Prestamo— con responsabilidades explícitas, relaciones dibujadas y un diagrama objetivo que guiará el resto del módulo. También sabes que la POO no es gratis: cuesta indirección, ceremonia y riesgo de sobrediseño, y solo se paga sola cuando el software tiene que crecer.
Tienes el plano. En la lección siguiente, Clases y Objetos, empiezas a construir: declararás la clase Libro con su sintaxis exacta, verás qué valor toman los campos antes de asignarles nada, crearás objetos con new siguiendo paso a paso qué ocurre en la pila y en el heap, descubrirás qué significa de verdad un NullPointerException y por qué dos referencias al mismo objeto pueden provocar sorpresas desagradables. Al terminarla, "Java Efectivo", "Patrones de Diseño" y "Refactorización" habrán dejado de ser cadenas de texto sueltas para convertirse en tres objetos con vida propia dentro de BiblioTechApp.
Curso de Programación en Java
Módulo 1: Introducción a Java
- Introducción a Java
- Configuración del Entorno de Desarrollo
- Sintaxis y Estructura Básica
- Variables y Tipos de Datos
- Operadores
- Entrada y Salida por Consola
- Tu Primer Programa Completo: BiblioTech
Módulo 2: Flujo de Control
- Sentencias Condicionales
- Bucles
- Sentencias Switch
- Break y Continue
- Depuración y Trazas de Ejecución
- Proyecto: Menú Interactivo de BiblioTech
Módulo 3: Programación Orientada a Objetos
- Introducción a la POO
- Clases y Objetos
- Métodos
- Constructores
- Herencia
- Polimorfismo
- Encapsulamiento
- Abstracción
- La Clase Object: equals, hashCode y toString
Módulo 4: Programación Orientada a Objetos Avanzada
- Interfaces
- Clases Abstractas
- Clases Internas
- Clases Anónimas
- Expresiones Lambda
- Interfaces Funcionales y Referencias a Métodos
- Enumeraciones y Registros
Módulo 5: Estructuras de Datos y Colecciones
- Arreglos
- El Framework de Colecciones
- ArrayList
- LinkedList
- HashMap
- HashSet
- Cola y Deque
- Pila
- Ordenación y Búsqueda en Colecciones
Módulo 6: Manejo de Excepciones
- Introducción a las Excepciones
- Bloque Try-Catch
- Throw y Throws
- Excepciones Personalizadas
- Bloque Finally
- Try-with-resources y AutoCloseable
- Estrategias de Manejo de Errores y Logging
Módulo 7: Entrada/Salida de Archivos
- Lectura de Archivos
- Escritura de Archivos
- Flujos de Archivos
- BufferedReader y BufferedWriter
- Serialización
- La API NIO.2: Path y Files
- Formatos de Intercambio: CSV y Properties
Módulo 8: Multihilo y Concurrencia
- Introducción al Multihilo
- Creación de Hilos
- Ciclo de Vida de un Hilo
- Sincronización
- Utilidades de Concurrencia
- Colecciones Concurrentes y Variables Atómicas
- Tareas Asíncronas con CompletableFuture
Módulo 9: Redes
- Introducción a las Redes
- Sockets
- ServerSocket
- DatagramSocket y DatagramPacket
- URL y HttpURLConnection
- El Cliente HTTP Moderno
Módulo 10: Temas Avanzados
- Genéricos
- Anotaciones
- Reflexión
- Características de Java 8: Streams y Optional
- Fechas y Horas con java.time
- Java 9 y Más Allá
- Memoria, Recolección de Basura y Rendimiento
Módulo 11: Frameworks y Librerías de Java
- Introducción a los Frameworks de Java
- Spring Framework
- Hibernate
- JUnit
- Maven
- Pruebas Avanzadas con Mockito
- Librerías Esenciales del Ecosistema
