Ejercicios Prácticos: La POO en "TechEvents Platform"
¡Hola, futuro arquitecto de software!
Bienvenidos a la fase práctica de la Programación Orientada a Objetos. En este conjunto de ejercicios, vamos a sumergirnos en el desarrollo de "TechEvents Platform", una aplicación de gestión de eventos tecnológicos. Imagina que somos un equipo de desarrollo que necesita diseñar y construir los cimientos de esta plataforma, utilizando los principios de la POO que acabamos de explorar.
El objetivo es modelar entidades del mundo real (como Evento, Participante, Ponente, Ubicacion) como clases en Java, definir sus atributos, sus comportamientos y cómo interactúan entre sí. Esta es la base de cualquier sistema robusto y escalable. Prepárense para aplicar conceptos como la encapsulación, los constructores, los getters, setters y los miembros estáticos para construir un sistema coherente y funcional.
Cada ejercicio les desafiará a pensar como diseñadores y programadores, pasando de la especificación a la implementación en código Java. ¡Manos a la obra!
Ejercicios de Consolidación
1) Diseñando la Plataforma: Diagrama de Clases UML para 'TechEvents' | Nivel: Fácil
Objetivo: Representar gráficamente las entidades principales de la plataforma 'TechEvents Platform' y sus relaciones utilizando un diagrama de clases UML.
Tarea a realizar:
Basándote en la descripción de una plataforma de gestión de eventos, identifica las principales clases (entidades), sus atributos más relevantes (al menos 3 por clase) y sus métodos clave (al menos 2 por clase, incluyendo constructores o getters/setters si los consideras esenciales).
Considera las siguientes entidades iniciales:
* Evento: Un evento tiene un título, una fecha, una descripción, una capacidad máxima de participantes y un precio.
* Participante: Cada participante tiene un nombre, apellidos, email, y puede registrarse en un evento.
* Ubicacion: Un evento se celebra en una ubicación con un nombre, dirección y capacidad física.
Crea un diagrama de clases UML (puedes usar la sintaxis de Mermaid.js vista en los materiales) que muestre:
1. Las tres clases (Evento, Participante, Ubicacion).
2. Los atributos (private) de cada clase con sus tipos de datos.
3. Los métodos (public) de cada clase (al menos 2 por clase, los constructores cuentan como método).
4. Las relaciones entre estas clases (por ejemplo, un Evento tiene una Ubicacion, un Participante se registra en un Evento). Indica el tipo de relación (asociación, agregación, composición) y su cardinalidad (1 a muchos, 1 a 1, etc.).
Aplicación en el Mundo Real:
Diseñar diagramas UML es una habilidad fundamental en el desarrollo de software. Permite a los equipos visualizar la arquitectura de la aplicación, discutir el diseño antes de escribir código y asegurar que todos los miembros tienen una comprensión común de las entidades del sistema. Es una herramienta clave para la comunicación técnica y la documentación.
2) Creación de la Clase Evento: El Alma de la Plataforma | Nivel: Fácil
Objetivo: Implementar la clase Evento en Java, aplicando los conceptos de atributos, constructores y encapsulación.
Setup Inicial:
Asegúrate de tener un entorno de desarrollo Java (IDE como IntelliJ IDEA o VS Code con el JDK 21).
Tarea a realizar:
Crea una nueva clase Java llamada Evento. Esta clase debe cumplir con los siguientes requisitos:
-
Atributos:
titulo(String): El nombre del evento.fecha(String): La fecha del evento (por simplicidad, usaStringpor ahora, aunque en un futuro usaríamosLocalDate).descripcion(String): Una breve descripción del evento.capacidadMaxima(int): El número máximo de participantes.precio(double): El coste de la entrada al evento.- Todos los atributos deben ser
privatepara asegurar la encapsulación.
-
Constructor:
- Un constructor público que reciba
titulo,fecha,descripcion,capacidadMaximaypreciocomo parámetros. - El constructor debe inicializar todos los atributos de la clase con los valores proporcionados. Usa
thispara desambiguar si los nombres de los parámetros coinciden con los de los atributos.
- Un constructor público que reciba
-
Métodos (Getters):
- Implementa métodos
publicgetpara cada uno de los atributos, permitiendo consultar sus valores desde fuera de la clase. Ejemplo:public String getTitulo().
- Implementa métodos
-
Método
toString():- Sobreescribe el método
toString()para que devuelva una representación enStringdel evento, incluyendo todos sus atributos de forma legible. Ejemplo:"Evento: [Título], Fecha: [Fecha], Precio: [Precio]€".
- Sobreescribe el método
-
Clase
Mainpara Pruebas:- Crea una clase
Main(oAppEventos) con un métodomain. - Dentro de
main, crea al menos dos objetosEventodiferentes, utilizando el constructor que has definido. - Imprime los detalles de cada evento utilizando su método
toString(). - Accede a al menos un atributo de cada evento usando su
gettere imprímelo por separado.
- Crea una clase
Aplicación en el Mundo Real:
La creación de clases es el primer paso en la programación orientada a objetos. Encapsular la lógica de una entidad en una clase bien definida mejora la modularidad, facilita el mantenimiento y permite reutilizar el código en diferentes partes de la aplicación.
3) Mejorando la Gestión de Stock: Producto con Encapsulación y Setters | Nivel: Fácil
Objetivo: Crear la clase Producto para la tienda de merchandising de 'TechEvents Platform', implementando atributos, constructor y la encapsulación con getters y setters (incluyendo validación).
Tarea a realizar:
Crea una clase Producto con las siguientes características:
-
Atributos
private:nombre(String)precio(double)stock(int)idProducto(String): Generado automáticamente o asignado de forma única, puede ser un simpleStringpor ahora.
-
Constructor:
- Un constructor que reciba
idProducto,nombre,precioystock.
- Un constructor que reciba
-
Getters para todos los atributos.
-
Setters para
precioystock:- El
setPreciodebe asegurar que el precio nunca sea negativo. Si se intenta establecer un precio negativo, debe dejar el precio sin cambios o establecerlo a 0.0, e imprimir un mensaje de advertencia. - El
setStockdebe asegurar que el stock nunca sea negativo. Si se intenta establecer un stock negativo, debe dejar el stock sin cambios o establecerlo a 0, e imprimir un mensaje de advertencia.
- El
-
Método
toString():- Sobreescribe
toString()para proporcionar una representación legible delProducto.
- Sobreescribe
-
Clase
Mainpara Pruebas:- En tu clase
Main, crea al menos dos objetosProducto. - Demuestra el uso de los
getters. - Demuestra el funcionamiento de los
setterscon valores válidos e inválidos, observando los mensajes de advertencia.
- En tu clase
Aplicación en el Mundo Real:
La encapsulación con setters y validaciones es crucial para mantener la integridad de los datos en cualquier sistema. Evita estados inconsistentes o inválidos de los objetos, lo que reduce bugs y hace el software más robusto y fiable, especialmente en transacciones comerciales.
4) Flexibilidad en la Creación de Objetos: Sobrecarga de Constructores para Participante | Nivel: Fácil
Objetivo: Implementar la clase Participante con múltiples constructores (sobrecarga) para permitir diferentes formas de inicialización.
Tarea a realizar:
Crea una clase Participante con las siguientes especificaciones:
-
Atributos
private:idParticipante(String): Identificador único (puedes autogenerar uno simple o pedirlo).nombre(String)apellidos(String)email(String)registrado(boolean): Indica si el participante ya ha completado su registro (por defectofalse).
-
Sobrecarga de Constructores:
- Constructor por defecto: Inicializa
idParticipantecon un valor por defecto (ej. "GEN_000"),nombreyapellidoscomo "Desconocido",emailcomo "sin_email@example.com", yregistradoafalse. - Constructor con nombre y email: Recibe
nombreyemail.apellidosserá "No proporcionado",idParticipantese autogenera (ej. "PART_" + un número secuencial o aleatorio simple), yregistradoatrue(asumimos que al dar estos datos ya se registra). - Constructor completo: Recibe
idParticipante,nombre,apellidos,emailyregistrado.
- Constructor por defecto: Inicializa
-
Getters para todos los atributos.
-
Método
toString():- Sobreescribe
toString()para mostrar los detalles del participante.
- Sobreescribe
-
Clase
Mainpara Pruebas:- En tu clase
Main, crea un objetoParticipanteusando cada uno de los constructores. - Imprime los detalles de cada participante para verificar su correcta inicialización.
- En tu clase
Aplicación en el Mundo Real:
La sobrecarga de constructores es esencial para proporcionar flexibilidad en la creación de objetos. Permite a los desarrolladores instanciar objetos con diferentes niveles de detalle o en diferentes estados iniciales, adaptándose a las necesidades del flujo de la aplicación (ej. registro rápido vs. registro completo).
5) this() para Evitar Duplicidad: Refactorizando Ubicacion | Nivel: Fácil
Objetivo: Refactorizar la clase Ubicacion para usar encadenamiento de constructores (this()) y centralizar la lógica de inicialización.
Setup Inicial:
Partiendo de una clase Ubicacion similar a la definida en el ejercicio 1 o 2.
Tarea a realizar:
Crea o modifica la clase Ubicacion con las siguientes características:
-
Atributos
private:nombre(String)direccion(String)capacidadTotal(int): La capacidad máxima de personas.tieneParking(boolean): Indica si la ubicación dispone de parking (por defectofalse).
-
Constructores sobrecargados utilizando
this():- Constructor completo:
public Ubicacion(String nombre, String direccion, int capacidadTotal, boolean tieneParking). Este será el constructor "principal" que inicialice todos los atributos. - Constructor con datos esenciales:
public Ubicacion(String nombre, String direccion, int capacidadTotal). Este constructor debe llamar al constructor completo, estableciendotieneParkingafalsepor defecto. - Constructor básico:
public Ubicacion(String nombre, String direccion). Este constructor debe llamar al anterior, estableciendocapacidadTotala0por defecto ytieneParkingafalse.
- Constructor completo:
-
Getters para todos los atributos.
-
Método
toString():- Sobreescribe
toString()para mostrar todos los detalles de la ubicación.
- Sobreescribe
-
Clase
Mainpara Pruebas:- Crea una instancia de
Ubicacionusando cada uno de los tres constructores. - Imprime cada objeto para verificar que los valores por defecto se establecen correctamente a través del encadenamiento.
- Crea una instancia de
Aplicación en el Mundo Real:
El uso de this() para el encadenamiento de constructores es una técnica fundamental para escribir código DRY (Don't Repeat Yourself). Evita la duplicación de lógica de inicialización, hace el código más limpio, más fácil de leer y mucho más mantenible, ya que un cambio en la inicialización básica solo necesita hacerse en un único lugar.
6) El Bug del Contador de Participantes: Depuración con Atributos Estáticos | Nivel: Medio
Objetivo: Identificar y corregir un bug relacionado con la implementación incorrecta de un contador de instancias utilizando un atributo de instancia en lugar de uno estático.
Setup Inicial:
Se te proporciona el siguiente código incompleto para la clase Participante.
// Participante.java (CON BUG)
import java.util.UUID;
public class Participante {
private String idParticipante;
private String nombre;
private String email;
// BUG: Este atributo DEBERÍA ser estático
private int contadorParticipantes;
public Participante(String nombre, String email) {
this.idParticipante = "PART_" + UUID.randomUUID().toString().substring(0, 4).toUpperCase();
this.nombre = nombre;
this.email = email;
this.contadorParticipantes++; // Incrementa el contador
}
public int getContadorParticipantes() {
return contadorParticipantes;
}
@Override
public String toString() {
return "ID: " + idParticipante + ", Nombre: " + nombre + ", Email: " + email + ", Contador (incorrecto): " + contadorParticipantes;
}
}
// Main.java (para probar el bug)
public class Main {
public static void main(String[] args) {
Participante p1 = new Participante("Ana García", "ana@example.com");
Participante p2 = new Participante("Luis Pérez", "luis@example.com");
Participante p3 = new Participante("Marta Soto", "marta@example.com");
System.out.println(p1);
System.out.println(p2);
System.out.println(p3);
System.out.println("\nContador de P1: " + p1.getContadorParticipantes());
System.out.println("Contador de P2: " + p2.getContadorParticipantes());
System.out.println("Contador de P3: " + p3.getContadorParticipantes());
System.out.println("¿Número total de participantes creados? Esperado: 3. Obtenido: " + p3.getContadorParticipantes());
}
}
Tarea a realizar:
- Analiza el código: Ejecuta el código proporcionado. Observa la salida e identifica el comportamiento inesperado del
contadorParticipantes. - Explica el bug: ¿Por qué el
contadorParticipantesno muestra el número total de participantes creados, sino siempre1para cada uno? Relaciona esto con el concepto de miembros de instancia vs. miembros de clase. - Corrige el código: Modifica la clase
Participantepara que elcontadorParticipantes(renombrado atotalParticipantesCreadospara mayor claridad) sea un atributostaticy cuente correctamente el número total de instancias deParticipantecreadas. - Adapta el acceso: Asegúrate de que el acceso a este contador estático se realice de la forma recomendada (
Clase.atributoEstatico) tanto para incrementarlo en el constructor como para consultarlo en la claseMain. - Verifica la corrección: Ejecuta el código modificado y confirma que la salida ahora muestra el recuento total de participantes correctamente.
Aplicación en el Mundo Real:
Depurar y entender el comportamiento de los miembros static es crítico. Los errores en su uso pueden llevar a datos inconsistentes en toda la aplicación, difíciles de rastrear. Este ejercicio simula un escenario común donde un atributo que debería ser compartido globalmente se implementa erróneamente por instancia.
Ejercicios de Refuerzo
7) Gestión de 'TechTokens': Atributos Estáticos y Métodos de Utilidad | Nivel: Medio
Objetivo: Implementar una clase TechTokens que gestione una moneda virtual común para la plataforma, utilizando atributos y métodos estáticos.
Tarea a realizar:
En la plataforma "TechEvents Platform", los usuarios ganan "TechTokens" por participar y pueden canjearlos. Vamos a crear una clase para gestionar aspectos globales de esta moneda.
-
Clase
TechTokens:- Crea una clase llamada
TechTokens. Esta clase no debe poder instanciarse (pista: ¿qué tipo de constructor lo impide?). - Atributo Estático
private:tasaConversionEuro(double): Representa cuántos TechTokens equivale 1 Euro. Inicialízalo a10.0(1€ = 10 TT). - Atributo Estático
private:nombreMoneda(String): El nombre de la moneda, inicialízalo a "TechTokens". - Método Estático
public:convertirEurosATokens(double euros): Recibe una cantidad en euros y devuelve la cantidad equivalente en TechTokens. - Método Estático
public:getNombreMoneda(): Devuelve el nombre de la moneda.
- Crea una clase llamada
-
Clase
Mainpara Pruebas:- En tu clase
Main, utiliza los métodos estáticos deTechTokenspara realizar y mostrar las siguientes operaciones:- Consultar el nombre de la moneda.
- Calcular cuántos TechTokens se obtienen por 50.00€.
- Calcular cuántos Euros son 250 TechTokens.
- En tu clase
Pista:
Recuerda que los métodos y atributos estáticos se acceden directamente a través del nombre de la clase, sin necesidad de crear un objeto: NombreClase.metodoEstatico().
Aplicación en el Mundo Real:
Las clases de utilidad con miembros estáticos son omnipresentes en el desarrollo. La clase Math de Java es el ejemplo perfecto. Se usan para encapsular reglas de negocio o cálculos universales que no dependen del estado de ningún objeto específico.
8) final y el ADN del Objeto: La Clase Ponente | Nivel: Medio
Objetivo: Utilizar la palabra clave final en atributos de instancia para asegurar que la identidad de un objeto no cambie una vez creado.
Tarea a realizar:
Crea la clase Ponente para la plataforma. La información de un ponente, como su identificador y su nombre, no debe poder cambiar una vez que se ha asignado.
-
Clase
Ponente:- Atributos
private final:idPonente(String)nombreCompleto(String)
- Atributos
privateno-final:temaPrincipal(String)tarifaHora(double)
- Atributos
-
Constructor:
- Crea un constructor que reciba todos los atributos. Obligatoriamente, el constructor debe inicializar los atributos
final.
- Crea un constructor que reciba todos los atributos. Obligatoriamente, el constructor debe inicializar los atributos
-
Métodos:
- Implementa
getterspara todos los atributos (incluyendo losfinal). - Implementa
setterssolo para los atributos no-final(temaPrincipalytarifaHora). - Añade un método
calcularCostoCharla(int horas)que devuelvatarifaHora * horas.
- Implementa
-
Intento de Setter para un
final:- Intenta crear un
setterparaidPonente(public void setIdPonente(String nuevoId)). Observa el error de compilación. Incluye el comentario sobre el error en tu solución.
- Intenta crear un
-
Clase
Mainpara Pruebas:- Crea un objeto
Ponente. - Intenta modificar un atributo
final(esto debe fallar en la compilación). - Modifica con éxito un atributo no-
final(tarifaHora). - Imprime el costo de una charla de 4 horas.
- Crea un objeto
Aplicación en el Mundo Real:
El uso de final es un pilar de la programación defensiva. Se utiliza en identificadores únicos (ID, UUID), nombres, o cualquier valor que deba permanecer inalterable. Asegura que el estado fundamental de un objeto no pueda ser modificado accidentalmente, lo cual es vital en entornos multihilo o sistemas de bases de datos.
9) Paso por Valor en el Mundo Real: Simulación de Transferencia de Fondos | Nivel: Medio
Objetivo: Comprender y demostrar las diferencias en el paso de parámetros (por valor de primitivos vs. por valor de referencia) en un contexto de objetos del mundo real.
Setup Inicial:
Utiliza la clase CuentaBancaria del material teórico como base (simplificada para solo tener saldo).
// CuentaBancaria.java (Simplificada para el ejercicio)
public class CuentaBancaria {
private double saldo;
public CuentaBancaria(double saldoInicial) {
this.saldo = saldoInicial;
}
public double getSaldo() { return saldo; }
public void setSaldo(double nuevoSaldo) { this.saldo = nuevoSaldo; }
public void ingresar(double cantidad) {
if (cantidad > 0) {
this.saldo += cantidad;
System.out.println("Ingreso realizado. Nuevo saldo: " + this.saldo);
}
}
}
Tarea a realizar:
Crea una clase GestorFondos con dos métodos estáticos y realiza pruebas en Main.
- Clase
GestorFondos:- Método Estático A (Paso de Primitivo):
public static void intentarModificarMonto(double monto) { monto = 0.0; // Se intenta modificar el valor recibido System.out.println(" [Dentro de A] Monto modificado a: " + monto); } - Método Estático B (Paso de Objeto):
public static void transferir(CuentaBancaria cuentaOrigen, double cantidad) { System.out.println(" [Dentro de B] Saldo inicial en cuenta origen: " + cuentaOrigen.getSaldo()); cuentaOrigen.ingresar(-cantidad); // ¡BUG: Intenta retirar de forma NO segura! (se ingresa con valor negativo) cuentaOrigen.setSaldo(cuentaOrigen.getSaldo() - cantidad); // Simulación de retiro System.out.println(" [Dentro de B] Saldo final en cuenta origen: " + cuentaOrigen.getSaldo()); }
- Método Estático A (Paso de Primitivo):
-
Clase
Main(Pruebas):- Prueba 1 (Primitivo): Declara un
doublellamadomontoTransferir = 100.0. Llama aGestorFondos.intentarModificarMonto(montoTransferir). Imprime el valor demontoTransferirdespués de la llamada. - Prueba 2 (Objeto): Crea un objeto
CuentaBancariallamadomiCuentacon saldo inicial500.0. Llama aGestorFondos.transferir(miCuenta, 50.0). Imprime el saldo demiCuentadespués de la llamada.
- Prueba 1 (Primitivo): Declara un
-
Análisis: En los comentarios del
Main, explica por qué el valor demontoTransferirno cambió, pero el saldo demiCuentasí que se modificó, aun cuando Java solo usa "paso por valor".
Aplicación en el Mundo Real:
En el desarrollo de APIs y librerías, es fundamental que los desarrolladores entiendan qué información se está pasando a un método y si los cambios internos afectarán al objeto que se pasa como argumento. La mala comprensión de esto es una fuente constante de bugs sutiles en la manipulación de objetos.
Ejercicios de Ampliación
10) Diseño de un Sistema de Notificaciones Modular | Nivel: Alto
Objetivo: Diseñar e implementar una jerarquía básica de clases para un sistema de notificaciones, aplicando herencia y polimorfismo (introducción conceptual) y el uso de constantes estáticas.
Tarea a realizar:
La plataforma necesita enviar notificaciones. Vamos a modelar las notificaciones como una clase base que luego será extendida.
-
Clase de Utilidad
ConfiguracionNotificacion:- Crea una clase
ConfiguracionNotificacionque no sea instanciable. - Define una constante
public static final String REMITENTE_DEFAULT = "no-reply@techevents.com"; - Define una constante
public static final int MAX_LONGITUD_TEXTO = 500;
- Crea una clase
-
Clase Base
Notificacion:- Define la clase
Notificacioncon los siguientes atributosprivate:remitente(String)destinatario(String)mensaje(String)
- Asegura la encapsulación con
getters. - El constructor debe recibir
destinatarioymensaje. Elremitentedebe tomar el valor por defecto de la constante estáticaREMITENTE_DEFAULTde la claseConfiguracionNotificacion. - El constructor debe recortar el
mensajesi superaMAX_LONGITUD_TEXTO.
- Define la clase
-
Método de Comportamiento Polimórfico:
- Añade un método
public String enviar()que devuelve el texto:"Enviando Notificación al [Destinatario] desde [Remitente]: [Mensaje Recortado/Completo]".
- Añade un método
-
Clase
Mainpara Pruebas:- Crea un objeto
Notificacioncon un mensaje muy largo (ej. más de 500 caracteres). - Crea otro objeto
Notificacioncon un mensaje corto. - Llama al método
enviar()en ambos y comprueba que el remitente es el por defecto y el mensaje largo ha sido recortado.
- Crea un objeto
Peer Review (Revisión por Pares):
Pídele a un compañero que revise tu implementación de la lógica de recorte del mensaje en el constructor. ¿Ha respetado el principio de encapsulación y ha usado correctamente las constantes estáticas? Pídele que te sugiera una alternativa para el recorte de texto sin usar la constante estática de longitud máxima, para discutir pros y contras.
Aplicación en el Mundo Real:
Este ejercicio modela cómo las grandes aplicaciones manejan tareas como el envío de correos o SMS. Las configuraciones globales se definen en clases estáticas, y los objetos base (como Notificacion) gestionan la lógica común de negocio (como el remitente o el límite de caracteres).
11) El Patrón Singleton para el Gestor de Conexiones | Nivel: Alto
Objetivo: Implementar el patrón de diseño Singleton para la clase GestorConexionBD, garantizando que solo exista una única instancia de este recurso en toda la aplicación.
Tarea a realizar:
En la plataforma, solo debe haber un gestor de conexiones a la base de datos para controlar los recursos. Utiliza el patrón Singleton para asegurar esto.
-
Clase
GestorConexionBD:- Atributo
private static:instanciade tipoGestorConexionBD. Inicializado anull. - Atributo
private:urlConexion(String). Inicializada en el constructor a "jdbc:oracle:thin:@servidor_prod:1521:XE". - Constructor
private: El constructor debe serprivate. Imprime un mensaje:"Se ha creado la única instancia del Gestor de Conexión." - Método
public static:getInstance(): Este es el punto de acceso global.- Debe verificar si
instanciaesnull. Si lo es, crea la nueva y única instancia (new GestorConexionBD()) y la asigna ainstancia. - Si no es
null, simplemente devuelve la instancia existente.
- Debe verificar si
- Método
publicde instancia:conectar(): Imprime"Conectando a la BD: " + urlConexion.
- Atributo
-
Clase
Mainpara Pruebas:- Prueba 1: Llama a
GestorConexionBD.getInstance()dos veces, asignando el resultado a dos variables diferentes (conexion1yconexion2). - Verificación: Imprime el resultado de comparar las dos referencias (
conexion1 == conexion2). Debería sertrue. - Prueba de unicidad: Comprueba la salida. Solo se debe imprimir el mensaje del constructor UNA sola vez.
- Llama al método
conectar()en ambas variables.
- Prueba 1: Llama a
Peer Review (Revisión por Pares):
Pídele a un compañero que intente crear una segunda instancia del GestorConexionBD sin usar el método getInstance() (por ejemplo, con new GestorConexionBD()). Debe obtener un error de compilación. Pídele que te explique por qué el constructor debe ser privado.
Aplicación en el Mundo Real:
El Singleton es uno de los patrones de diseño más utilizados. Es vital para recursos de aplicación que deben ser únicos: gestores de bases de datos, gestores de logs, configuración de sistema y thread pools. Aplicarlo correctamente asegura el control estricto de los recursos compartidos.
12) Reto de Modelado: Creando una Clase de Utilidad de Propósito Múltiple | Nivel: Alto
Objetivo: Consolidar el uso de static, final y la no-instanciación, creando una clase de servicio o utilidad que resuelva cálculos para la plataforma.
Tarea a realizar:
Crea una clase UtilidadEvento que actúe como un conjunto de herramientas para la gestión de eventos.
-
Clase
UtilidadEvento:- Haz que esta clase no sea instanciable (constructor privado).
- Constante Estática
final:IVA_APLICABLE(double), con valor0.21(21%). - Método Estático:
calcularPrecioFinal(double precioBase): Recibe un precio base y devuelve el precio con el IVA aplicado. - Método Estático:
generarCodigoAsistencia(String email, String fecha):- Genera y devuelve un código de asistencia único (String).
- El código debe ser la concatenación de las primeras 3 letras del email, las últimas 4 cifras de la fecha (asumiendo que la fecha es
DD/MM/YYYY) y un número aleatorio de 3 dígitos (ej:System.currentTimeMillis() % 1000). - Ejemplo:
email="pepe@corp.com", fecha="20/11/2024"-> Código:PEPE2024XXX(donde XXX es el aleatorio).
- Método Estático:
esFinDeSemana(int diaDeLaSemana): Recibe un entero representando el día de la semana (1=Lunes,7=Domingo) y devuelvetruesi es fin de semana (6o7).
-
Clase
Mainpara Pruebas:- Muestra el cálculo del precio final para una entrada de 100.00€.
- Genera e imprime el código de asistencia para el email "alicia@events.net" y la fecha "05/10/2024".
- Comprueba si el día 1 (Lunes) y el día 7 (Domingo) son fin de semana.
Peer Review (Revisión por Pares):
Pídele a un compañero que revise tu método generarCodigoAsistencia. ¿Qué posibles problemas de robustez o seguridad tiene este método? ¿Cómo podría mejorarse usando la clase UUID o SecureRandom en lugar de la forma simple que se pide? Discute estas alternativas.
Aplicación en el Mundo Real:
La creación de códigos únicos (como códigos QR, códigos de barras o claves de licencia) y la gestión de cálculos fiscales son tareas de utilidad comunes en el desarrollo empresarial. Este ejercicio simula la centralización de estas lógicas en una clase de servicios.