Proyecto 3 - Galeria
Proyecto 3 - Galeria
Proyecto 3 - Galeria
Instrucciones generales
Para este proyecto usted puede (debe) empezar a trabajar sobre su entrega para el proyecto #2, pueden hacerse
cambios sobre el diseño original para acomodar mejor los requerimientos de este proyecto.
El proyecto DEBE desarrollarse en los mismos grupos del proyecto #2.
Debe haber una visualización de alto nivel que muestre gráficamente la cantidad de ventas realizadas a lo largo
de un año. Un ejemplo basado en la matriz de actividades de GitHub se puede ver en la siguiente imagen (donde
las casillas oscuras indican el valor total de las ventas en ese día), pero usted puede seleccionar cualquier otra
representación que quiera.
Nuevo requerimiento: Pago con Tarjeta de Crédito
Buscaremos ahora que su aplicación esté cada vez más lista para recibir pagos con tarjeta de crédito: la aplicación
debe incluir un mecanismo flexible para integrarse con pasarelas de pago (PayU, Paypal, etc.). Todas estas
pasarelas ofrecen un servicio que recibe la información de una tarjeta de crédito (incluyendo la información del
dueño) y la información de un pago que se debe hacer (monto, número de cuenta y número de transacción), y
retornan un resultado que indica si el pago se realizó de forma exitosa o si hubo algún problema particular (ej. los
datos de la tarjeta están equivocados, la tarjeta no tiene cupo suficiente, la tarjeta está reportada, etc.). En la
realidad cada pasarela tiene pequeñas diferencias con este modelo, pero es imaginable un servicio abstracto de
pago detrás del cuál pueda estar cualquier pasarela.
Su aplicación debe permitir ahora que se pueda hace el pago (simulado) con una tarjeta de crédito: en el momento
del pago, el empleado seleccionará una de las pasarelas de pago disponibles, digitará la información de la tarjeta
y de su dueño, y procederá a realizar el cobro.
Su aplicación debe poder soportar con facilidad que se cambie la implementación de las pasarelas: debe haber un
archivo de texto plano con la configuración de las pasarelas disponibles. Cada línea en ese archivo será el nombre
de una clase Java que implemente una pasarela simulada. Las pasarelas simuladas deben simplemente crear un
archivo de texto con la traza de las transacciones que se hayan realizado y el resultado de cada una.
Ayuda: al final de este documento se encuentra una ayuda sobre el método forName() de la clase Class que le
será de mucha ayuda en este punto.
Por ejemplo, el archivo de configuración podría decir que hay 3 implementaciones de pasarelas llamadas
uniandes.dpoo.PayPal, uniandes.dpoo.Payu y uniandes.dpoo.Sire. Entonces, cuando se vaya a hacer el
pago, las opciones de pasarela que deben aparecerle al usuario serán PayPal, Payu y Sire. A medida que se vayan
haciendo pagos, se irán registrando en tres archivos (PayPal.log, Payu.txt, y Sire.json). En este ejemplo los tres
archivos son diferentes para ilustrar que cada implementación puede definir independientemente cómo hace el
registro.
El valor de su diseño dependerá de qué tan fácil sea soportar una nueva pasarela (ej. Apple Pay).
1. Realice el diseño y construya un documento de diseño donde presente el diseño con las justificaciones para
las decisiones clave que hayan tomado. El documento debe incluir por lo menos los siguientes elementos:
a. Al menos un diagrama de clases que incluya todas las clases del sistema, incluyendo sus relaciones,
atributos y métodos. Los diagramas deben cubrir tanto la interfaz como la parte del diseño dedicado
a la lógica de dominio.
b. Un diagrama de clases de alto nivel, que incluya todas las clases del sistema y sus relaciones.
c. Un diagrama de clases de alto nivel de la interfaz, que muestre qué elementos se incluye y cómo se
relacionan con los elementos del dominio.
Estos elementos NO son los únicos que debe incluir su documento. Con seguridad hay muchos más elementos
que usted considerará relevantes sobre su diseño.
2. Implemente el sistema que diseñó. Tenga en cuenta que los detalles de la implementación deben ser
coherentes tanto con el modelo de clases, como con los diagramas de secuencia que incluya dentro del
documento de diseño.
No se evaluarán implementaciones que no tengan un documento de diseño actualizado que las acompañe.
Entrega
1. Entregue un enlace al repositorio a través de Bloque Neón en la actividad designada como “Proyecto 3 -
Entrega Única”.
Hay algunos casos en los cuales el segundo punto no aplica porque no estamos seguros de cuál va a ser la clase
exacta del objeto obj: sabemos que debería ser una subclase de Clase1, pero no sabemos exactamente cuál. En
estos casos, necesitamos un mecanismo flexible que nos permita definir el nombre de la clase lo más tarde posible.
El siguiente fragmento de código resuelve el problema, usando tres métodos que posiblemente usted no ha usado
hasta ahora.
Class clase = Class.forName(nombreClase);
SuperClase obj = (SuperClase) clase.getDeclaredConstructor(null).newInstance(null);
Veamos ahora el uso de este mecanismo en un caso concreto. Queremos tener un celular que tiene la posibilidad
de guardar los datos de la agenda telefónica en diferentes tipos de archivos. Por ahora sabemos que los archivos
podrían ser CSV, JSON o XML, pero en el futuro podría haber otros tipos. Además, no queremos que nuestro
código defina explícitamente el tipo de archivo, por lo cual decidimos cargar dinámicamente la clase específica
que implementará la agenda y se encargará de escribir y leer los datos de los contactos.
El siguiente diagrama de clases muestra las clases que hacen parte de la solución:
• La clase abstracta AgendaTelefonica, que tiene una colección de contactos. Los métodos
guardarContactos y cargarContactos de esta clase son abstractos.
• Las clases AgendaCSV, AgendaJSON y AgendaXML que extienden AgendaTelefonica y le dan una
implementación a los métodos faltantes.
• La clase Celular, que tiene una agenda: el celular no sabe la clase exacta de ese objeto; sólo sabe que
pertenece a una subclase de AgendaTelefonica.
Las clases Contacto, AgendaTelefonica, AgendaCSV, AgendaJSON y AgendaXML no tienen nada que usted no
haya visto ya y sea capaz de reconstruir. La clase Celular es la que tiene cosas particulares relacionadas con
la carga dinámica de clases: estudie con cuidado el siguiente código y preste especial atención a estas dos
cosas:
• En el método main, se le pregunta al usuario por el nombre de la clase que se usará para la agenda. El
usuario debe digitar el nombre completo de la clase, incluyendo el nombre de los paquetes.
• En el constructor de la clase Celular, se carga la clase cuyo nombre llega como un String, se busca
un constructor sin parámetros y se crea un objeto que sea una instancia de esa clase.
Celular.java
public class Celular
{
// La agenda telefónica de este celular: no sabemos a qué clase pertenece
// exactamente
// el objeto; sólo sabemos que pertenece a una subclase de AgendaTelefónica
private AgendaTelefonica miAgenda;
/**
* Construye un nuevo celular e inicializa su agenda telefónica
*
* @param claseAgenda El nombre completo de la clase que se usará para
* construir la agenda
* @param archivoDatos El nombre del archivo que continene la información de la
* agenda
*/
public Celular(String claseAgenda, String archivoDatos)
{
try
{
// 1. Dado el nombre completo (claseAgenda), encontramos un objeto de la clase
// Class
Class clase = Class.forName(claseAgenda);
/**
* Le pide los contactos a la agenda e imprime el nombre de cada uno en la
* consola
*/
public void listarContactos()
{
miAgenda.getContactos().forEach(contacto ->
{
System.out.println(contacto.getNombre());
});
}
// Crea un nuevo celular indicando que la agenda debe ser una instancia
// de la clase que haya tecleado el usuario
Celular miCelular = new Celular(nombreClase, "./data/datos.csv");
// Celular miCelular = new Celular("celular.AgendaCSV", "./data/datos.csv");
miCelular.listarContactos();
}