UML Diagramas de clases (para diseño)
Índice 1. Por qué diagramas de clases de análisis y de diseño?. 2. Diagramas de clases de diseño.
Análisis y diseño Por qué diagramas de clases de análisis y diseño? En el análisis queremos contar unas cosas y en el diseño otras. Algunos símbolos de UML se adaptan mejor al análisis y otros al diseño. Al tener una paleta de herramientas más pequeña, dudamos menos.
Análisis y diseño Usaremos: generalización, agregación, composición, clases, paquetes, etc. No usaremos: asociaciones. Nuevos elementos: dependencias, realizaciones, nesting. Los paquetes ya no son subsistemas sino agrupaciones de clases. Usaremos estereotipos para reflejar características del diseño / plataforma de implementación.
Diagramas de clases de diseño
Relación de dependencia. Significa que un elemento es estructuralmente dependiente de otro elemento. Esto es, cambios en un elemento afectarán a cambios en el elemento dependiente. Clase A class A { B b;. } Clase B
Relación de implementación. Significa que un elemento implementa a otro. UML no define con precisión el significado de implementar. Habitualmente utilizado en interfaces Clase A Interfaz I +métodox() class A implements I { métodox() { ; } }.
Relación de nesting Aún no una traducción oficial ( anidamiento?). Define un elemento contenido dentro de otro. No existe en StarUML (estereotipar). <<nesting>> Clase A class Class1 {. class Class2 { ; } } Clase B
Estereotipos: Un nuevo tipo de elemento. Añade algo nuevo: una semántica o comportamiento, restricciones, métodos atributos. Útil para capturar detalles de la plataforma de implementación. cd Estereotipos Página Principal Vista Estereotipos: Web page. Servlet JSP. Link «link» link Controlador
Ejercicio: Una clase Venta contiene una lista de objetos LineaDeVenta. Deseamos implementar nuestro propio iterador (en Java) para recorrer todas las líneas de venta. Suponemos que las líneas de venta se almacenan en un array.
Venta LineaDeVenta +iterator(): java.util.iterator <<interface>> java.util.iterator +hasnext(): boolean +next(): LineaDeVenta +remove(): LineaDeVenta VentaInterador
Venta +iterator(): java.util.iterator 0..* +vendido LineaDeVenta <<nesting>> <<interface>> java.util.iterator +hasnext(): boolean +next(): LineaDeVenta +remove(): LineaDeVenta VentaInterador class Venta { LineaDeVenta[] vendido; Itertor<LineaDeVenta> iterator() { return new VentaIterator<LineaDeVenta> (); } } class VentaIterator implements Iterator<E> { } E next() {.. }
Una calculadora en JSF Modelar la operación suma (con éxito) <<CommandButton>> OpSuma <<JSFPanerGroup>> Result +rendered: boolean = false <<JSFPage>> CalculadoraForm <<JSFController>> CalculadoraControl +OpSuma() Calculadora +primernumero: int +segundonumero: int +resultado: int +suma() +resta() +multiplica() +divide() +getresultado()
/ : Usuario 1 : introduce número A() /CalculadoraForm / : OpSuma / : CalculadoraControl /c : Calculadora / : Result Interfaz de usuario. Controlador. Modelo. 2 : introduce número B() 3 : operación suma() 4 : c := getcalculadora() 5 : setprimernumero() 6 : setsegundonumero() 7 : OpSuma() 8 : suma() 9 : getresultado() 10 : setrendred() 11
<<CommandButton>> OpSuma / : OpSuma / : CalculadoraControl / : Calculadora / : Result / : Usuario <<JSFPage>> CalculadoraForm <<JSFController>> CalculadoraControl +OpSuma() <<JSFInjected>> Calculadora +primernumero: int +segundonumero: int +resultado: int +suma() +resta() +multiplica() +divide() 1 2 : OpSuma() 3 : suma() 4 : getresultado() 5 : setrendred() <<JSFPanerGroup>> Result +rendered: boolean = false 6
Ejercicio: ciclo de vida de un informe. Una primera versión es creada por un auxiliar administrativo. Después pasa al director para completar los detalles. Después pasa a un revisor. Cuando está revisada, se aprueba por el jefe de servicio.
Ejercicio [ fallos en versión preliminar ] / borrardatospreliminares() VersiónInicial introducirdatospreliminares [ datosvalidos() ] [ fallos en detalles ] VersiónPreliminar VersiónCompleta Revisión VersiónAprobada VersiónRevisada [ aprobada ] Inicial: vacío. Preliminar: datos preliminares. Completo: toda la información. Al retroceder a un estado anterior, se pierde toda la información almacenada.
StarUML incluye ayuda sobre los patrones y elementos ya predefinidos.
+estado Informe 1 DatosDelInforme Candidatas a ser una única clase. +introducirdatosbásicos() +validardatosbásicos() +borrardatosadicionales() Candidatas a ser clases internas. EstadoInicial 4 <<interface>> EstadoInforme EstadoPreliminar +versiónpreliminar() +versioncompleta() +versionvalidada() +versionaprobada() EstadoCompletado EstadoValidado <<runtimeexception>> ExceptionOperacionNoPermitidaEnEsteEstado EstadoAprobado
Usuario Dado que los propios estados son stateless, mejor reutilizar que crear (incluso compartidos por distintas instancias). <<create>> 1 i : Informe <<create>> 2 i.estado : EstadoInicial 3 : introducirdatosbásicos() 4 : versiónpreliminar() <<create>> 5 : validardatosbásicos() 6 i.estado : EstadoPreliminar
Cómo podemos asegurarnos de que los usuarios humanos del sistema no hagan lo que no deban? Mediante sus interfaces. Nunca debería llegarle a un usuario un error provocado por la excepción ExcepcionOperacionNoPermitidaEnEsteEstado (por eso es Runtime). Pero los programadores sí deben conocer las secuencias correctas y las secuencias incorrectas. Para ello tiene la especificación (máquina de estados). Además, probarán que, en ningún momento, ninguna secuencia de acciones del sistema arroja la excepción. Y, además, probarán que todas las secuencias erróneas lanzan la excepción (en el momento correcto). Lo cuál es imposible ( mutación de secuencias?).
Otros patrones complementarios. En cada estado puedo realizar cualquier operación. Aunque salte un error al intentar cambiar de estado, la operación ya se ha realizado. Cómo podemos invalidar operaciones según el estado?. Patrón decorador: Decorando los métodos del informe según el estado. Cada estado tiene su propio decorador los cuáles me redefinen los métodos a evitar.