Problema Se deberá desarrollar un sistema que permita gestionar las Ordenes de Despacho (O/D) de un pequeño distribuidor de productos. Particularmente el sistema deberá permitir generar, consultar, modificar y eliminar O/D, junto con todos los otros datos asociados. Ejemplo (incompleto) de desarrollo de una aplicación en Java Las O/D son documentos que contienen un número identificador, los datos del cliente al cual van dirigidas y una lista de productos con sus cantidades y precios a despachar. Se desea que al momento de generar la O/D, el sistema utilice los datos almacenados previamente relativos a clientes y productos. La aplicación, por lo tanto, deberá mantener también estos datos. Franco Guidi Polanco Escuela de Ingeniería Industrial Pontificia Universidad Católica de Valparaíso, Chile fguidi@ucv.cl Franco Guidi Polanco Problema (cont.) Modelo de Análisis: primera aproximación Ejemplo de una O/D: ACME, INC. O/D número precio total impuesto Nº 0162353 ORDEN DE DESPACHO 0..* RUT Cliente: 1.111.111-3 Razón Social: COYOTE Y ASOCIADOS Dirección: Camino Troncal 2734, Villa Alemana Teléfono: 64654522 Detalle Código Nombre L323 Lanzacohetes M001 Maíz para correcaminos P1189 Pintura invisible Franco Guidi Polanco 2 Unidad Cantidad Precio unit Total ($) un kg galón 2 50 2 $ $ 145.000 Total: $ 159.500 1..1 rut razón social dirección teléfono Producto en O/D cantidad 0..* Producto código nombre unidad precio unitario 15.500 31.000 2.000 100.000 7.000 14.000 Subtotal: Impuesto (10%): Cliente 0..* 14.500 3 Franco Guidi Polanco ACME, INC. Nº 0162353 ORDEN DE DESPACHO RUT Cliente: 1.111.111-3 Razón Social: COYOTE Y ASOCIADOS Dirección: Camino Troncal 2734, Villa Alemana Teléfono: 64654522 Detalle Código Nombre L323 Lanzacohetes M001 Maíz para correcaminos P1189 Pintura invisible Unidad Cantidad Precio unit Total ($) un kg galón 2 50 2 15.500 31.000 2.000 100.000 7.000 14.000 Subtotal: Impuesto (10%): $ $ 145.000 Total: $ 159.500 14.500 4 Modelo de Análisis: modelo refinado I Modelo de Análisis: modelo refinado II Notamos relación TODO-PARTE entre O/D y Producto en O/D O/D número precio total impuesto 0..* 1..1 Notamos que una actualización en los precios de producto, modificaría la información de O/D registradas. Luego es necesario registrar el precio unitario en el Producto en O/D: Cliente rut razón social dirección teléfono O/D número precio total impuesto 0..* 0..* Producto en O/D 0..* 1..1 cantidad Producto en O/D cantidad precio unitario Modelo de Análisis: comentarios respecto del modelo refinado II código 1..1 nombre unidad precio unitario Franco Guidi Polanco 6 :O/D número=162353 precio total=159500 impuesto=10% :Producto en O/D cantidad=2 precio unitario=15500 Cliente 1..1 rut :Producto en O/D razón social dirección teléfono cantidad=50 precio unitario=2000 :Producto en O/D cantidad=2 precio unitario=7000 Franco Guidi Polanco 0..* Diagrama de objetos: Cliente en O/D dirección teléfono Producto ¿Cómo se ve el modelo en un caso? Razonamiento análogo al anterior, nos puede conducir a cuestionar la relación entre O/D y Cliente: ¿Qué pasa si se actualizan los datos del cliente? (ej. cambio de teléfono?) 0..* rut razón social dirección teléfono 0..* código nombre unidad precio unitario 5 1..1 1..1 Cliente Producto Franco Guidi Polanco O/D número precio total impuesto 1..1 7 Franco Guidi Polanco :Cliente rut=“1.111.111-3” razón social= “COYOTE Y ASOC.” dirección=“camiino Troncal…” teléfono=“64654522” :Producto código=“L323” nombre=“Lanzacohetes” unidad=“un” precio unitario=15500 :Producto código=“M001” nombre=“Maíz para correcaminos” unidad=“kg” precio unitario=2000 :Producto código=“P1189” nombre=“Pintura invisible” unidad=“galón” precio unitario=7000 8 Modelo de Diseño: consideraciones a la primera aproximación Modelo de Diseño: primera aproximación ¿El precio total de la O/D será almacenado en una variable de instancia o calculado sumando los precios unitarios de los Productos en O/D?... No importa, encapsulemos el proceso de obtención dentro de un método. OrdenDespacho 0..* número impuesto 1..1 getPrecioTotal() Incluyendo como parámetro del constructor de O/D una referencia a Cliente. Podemos, incluso, generar una excepción en la instanciación de O/D si la referencia a cliente pasada por parámetro tiene valor null. Si admitimos un método setCliente, verificando que este método no contenga una referencia null. Cliente rut razónSocial dirección teléfono OrdenDespacho número impuesto Producto 0..* Producto en OD cantidad precioUnitario El modelo establece que una O/D debe estar asociada siempre a un Cliente ¿Podemos forzar esto? Sí: setCliente(c:Cliente) getPrecioTotal() OD(cliente:Cliente) código 1..1 nombre unidad precioUnitario 0..* Franco Guidi Polanco 9 Modelo de Diseño: segunda versión número: String impuesto: float 0..* ProductoEnOD Franco Guidi Polanco Cliente rut razónSocial dirección teléfono setCliente(c:Cliente){ if(c != null) cliente = c; } Franco Guidi Polanco 10 Navegabilidad: OrdenDespacho -número: String -impuesto: float setCliente(c:Cliente) getCliente(): Cliente getNumero(): int getPrecioTotal(): int OD(número:int, cliente:Cliente impuesto:float) cantidad:int precioUnitario:int setCantidad(c:int) getCantidad():int setPrecioUnitario(p:int) getPrecioUnitario():int 1..1 Modelo de Diseño: tercera versión Agregamos métodos y constructores OrdenDespacho 0..* 0..* 0..* 1..1 Producto código:String nombre:String unidad:String precioUnitario:int getCódigo():String getNombre():String getUnidad():String 1..1 setPrecioUnitario(p:int) getPrecioUnitario()String Producto(cod:String, nom:String, un:String, pu:int) Cliente rut:String razónSocial:String dirección:String teléfono:String getRut():String getRazónSocial():String getDirección():String getTeléfono():String Cliente(rut:String,rs:String, dir:String,tel:String) setCliente(c:Cliente) getCliente(): Cliente getNumero(): int getPrecioTotal(): int OD(número:int, cliente:Cliente impuesto:float) 0..* ProductoEnOD -cantidad:int -precioUnitario:int setCantidad(c:int) getCantidad():int setPrecioUnitario(p:int) getPrecioUnitario():int 11 Franco Guidi Polanco 0..* 0..* 1..1 Producto -código:String -nombre:String -unidad:String -precioUnitario:int getCódigo():String getNombre():String getUnidad():String 1..1 setPrecioUnitario(p:int) getPrecioUnitario()String Producto(cod:String, nom:String, un:String, pu:int) Cliente -rut:String -razónSocial:String -dirección:String -teléfono:String getRut():String getRazónSocial():String getDirección():String getTeléfono():String Cliente(rut:String,rs:String, dir:String,tel:String) 12 Modelo de Diseño: cuarta versión OrdenDespacho ¿Cómo agregamos productos a la O/D? OrdenDespacho -número: String -impuesto: float setCliente(c:Cliente) getCliente(): Cliente getNumero(): int getPrecioTotal(): int addProducto(p:Producto,cant:int) OD(número:int, cliente:Cliente impuesto:float) 0..* Modelo de Diseño: cuarta versión (completa) -número: String -impuesto: float setCliente(c:Cliente) 0..* 1..1 getCliente(): Cliente getNumero(): int getPrecioTotal(): int addProducto(p:Producto,cant:int) Producto OD(número:int, cliente:Cliente -código:String impuesto:float) -nombre:String -unidad:String -precioUnitario:int 0..* getCódigo():String getNombre():String ProductoEnOD getUnidad():String -cantidad:int 0..* 1..1 setPrecioUnitario(p:int) -precioUnitario:int getPrecioUnitario()String setCantidad(c:int) Producto(cod:String, getCantidad():int nom:String, un:String, setPrecioUnitario(p:int) pu:int) getPrecioUnitario():int Producto ProductoEnOD -cantidad:int -precioUnitario:int setCantidad(c:int) getCantidad():int setPrecioUnitario(p:int) getPrecioUnitario():int 0..* -código:String -nombre:String -unidad:String -precioUnitario:int 1..1 getCódigo():String getNombre():String getUnidad():String setPrecioUnitario(p:int) getPrecioUnitario()String Franco Guidi Polanco 13 ¿Cómo implementamos las asociaciones en Java? OrdenDespacho setCliente(c:Cliente) 0..* getCliente(): Cliente getNumero(): int getPrecioTotal(): int addProducto(p:Producto,cant:int) OD(número:int, cliente:Cliente impuesto:float) public class OrdenDespacho{ private String número; private float impuesto; private Cliente cliente; … } Franco Guidi Polanco 1..1 14 ¿Cómo implementamos las asociaciones en Java? -número: String -impuesto: float -rut:String -razónSocial:String -dirección:String -teléfono:String getRut():String getRazónSocial():String getDirección():String getTeléfono():String Cliente(rut:String,rs:String, dir:String,tel:String) setCliente(c:Cliente) getCliente(): Cliente getNumero(): int getPrecioTotal(): int addProducto(p:Producto,cant:int) OD(número:int, cliente:Cliente impuesto:float) 0..* Implementación de la asociación O/D con Cliente ProductoEnOD -cantidad:int -precioUnitario:int setCantidad(c:int) getCantidad():int setPrecioUnitario(p:int) getPrecioUnitario():int 15 getRut():String getRazónSocial():String getDirección():String getTeléfono():String Cliente(rut:String,rs:String, dir:String,tel:String) Franco Guidi Polanco OrdenDespacho Cliente -número: String -impuesto: float Cliente -rut:String -razónSocial:String -dirección:String -teléfono:String Franco Guidi Polanco Implementaciones alternativas de la asociación de O/D y Producto en O/D (entre otras) public class OrdenDespacho{ private String número; private float impuesto; private Cliente cliente; private ProductoEnOD[] productoEnOD; … } import java.util.Vector; public class OrdenDespacho{ private String número; private float impuesto; private Cliente cliente; private Vector productoEnOD; … } 16 ¿Cómo implementamos las asociaciones en Java? ProductoEnOD -cantidad:int -precioUnitario:int setCantidad(c:int) getCantidad():int setPrecioUnitario(p:int) getPrecioUnitario():int Producto -código:String -nombre:String 0..* 1..1 -unidad:String -precioUnitario:int getCódigo():String getNombre():String getUnidad():String setPrecioUnitario(p:int) getPrecioUnitario()String Producto(cod:String, nom:string, un:string, pu:int) Implementación de asociación entre ProductoEnOD y Producto ¿Cómo mantenemos los datos de O/D, Clientes y Productos en la aplicación? Podríamos manejarlos en arreglos o Vectores: public class SistemaOrdenes{ public static void main(String[] arg){ … Cliente[] cliente = new Cliente[10000]; OD[] od = new OD[10000]; Producto[] = new Producto[10000]; … } } public class ProductoEnOD{ private int cantidad; private int precioUnitario; private Producto producto; … } Franco Guidi Polanco 17 Observación a la utilización de arreglos La aplicación es responsable de manejar los arreglos (Clientes, O/D y Productos): identificar posiciones disponibles no acceder a posiciones inexistentes realizar búsquedas etc. Franco Guidi Polanco Franco Guidi Polanco 18 Conveniencia de utilizar colecciones public class SistemaOrdenes{ public static void main(String[] arg){ … Cliente[] cliente = new Cliente[10000]; OD[] od = new OD[10000]; Producto[] = new Producto[10000]; … // agregar un Cliente for(int i=0;i<cliente.length;i++){ if( cliente[i] == null ) … etc } Modelo de Diseño: ¿qué falta? Es conveniente utilizar clases que permitan mantener datos de Clientes, O/D y Productos: listaOD:Lista Nº01:OD Nº02:OD Nº99:OD listaProductos:Lista // agregar un Producto for(int i=0;i<producto.length;i++){ if( producto[i] == null ) … etc … } Perno:Producto Golilla:Producto listaClientes:Lista Inducap:Cliente 19 Franco Guidi Polanco Acme:Cliente Insumor:Cliente 20 Implementación de Listas Implementación de Listas public abstract class Lista{ private Object[] elem = new Object[10000]; private int posLibre = 0; Lista {abstract} -elemento:Object -posLibre:int agregar(o:Object) buscar(clave:String):Object {abstract} eliminar(clave:String) public boolean agregar(Object o){ if(posLibre < elem.length){ elem[posLibre] = o; posLibre++; return true; } return false; } La implementación de estas colecciones reduce las responsabilidades de la aplicación: public class SistemaOrdenes{ public static void main(String[] arg){ … ListaClientes listaCliente = new ListaClientes(); ListaOD listaOd = new ListaOD(); ListaProducto listaProducto= new ListaProductos(); … public abstract buscar(String clave); public boolean eliminar(Object o){ for(int i:=0; i<posLibre; i++ ){ if( elem[i]==o){ ... ListaOD ListaClientes ListaProductos buscar(clave:String):Object buscar(clave:String):Object buscar(clave:String):Object Franco Guidi Polanco // agregar un Cliente listaCliente.agregar( nuevoCliente ); } 21 Finalmente nuestro modelo: Respuesta: Sí. Pregunta ¿Cómo? Con uso adecuado de abstracciones (ver principio de inversión de dependencia). Tarea. ListaProductos 0..* OrdenDespacho 0..* 1..1 ProductoEnOD Además podríamos utilizar “Generics” de Java. Se sugiere revisar además el Java Collections Framework. Cliente 0..* 0..* 0..* 22 ¿Podríamos definir un único tipo de lista para manipular todas las colecciones? ListaClientes 0..* Franco Guidi Polanco Refinamiento sucesivo Lista {abstract} ListaOD // agregar un Producto listaProducto.agregar( nuevoProducto ); } 1..1 Producto ¿Qué diferencia existe entre las clases indicadas en celeste y las restantes clases? Franco Guidi Polanco 23 Franco Guidi Polanco 24