patronesparapersiste.. - Escuela Superior de Informática
Transcripción
patronesparapersiste.. - Escuela Superior de Informática
Patrones para persistencia (I) Ingeniería del Software II 1 Patrones para la construcción del esquema relacional En todos los ejemplos realizaremos transformaciones del siguiente diagrama de clases: Figura 1 1.1 Patrón "una clase, una tabla" Mediante este patrón, se construye una tabla por cada clase en la capa de dominio. Todas las clases que no sean abstractas se transforman en tablas. La herencia se representa mediante propagación de clave. En el caso de la Figura 1, puesto que no hay ninguna clase abstracta, el diagrama relacional sería el siguiente (Figura 2): Escuela Superior de Informática Universidad de Castilla-La Mancha Macario Polo Usaola 1 Figura 2 Suponiendo que la clase Vehículos fuera abstracta, habríamos obtenido el siguiente diagrama relacional (Figura 3): Figura 3 1.2 Patrón "un árbol de herencia, una tabla" Con este patrón, cada árbol de herencia se representa en una única tabla, que contendrá como columnas todos los atributos de todas las clases del árbol de herencia. Escuela Superior de Informática Universidad de Castilla-La Mancha Macario Polo Usaola 2 Mediante esta solución, habrá muchos registros en la tabla que tengan varias columnas a NULL. En el ejemplo de la Figura 1, el árbol de herencia que tiene como nodo raíz a la clase Vehículos se transformaría en la siguiente tabla: Figura 4 Al insertar información en la tabla de la Figura 4, se insertará el valor NULL en la columna "Toneladas" cuando se inserte un registro correspondiente a un coche, y NULL en "Potencia" cuando se inserte un camión. El diagrama relacional completo tendría esta forma: Figura 5 1.3 Patrón "un camino de herencia, una tabla" Con este patrón, se construye una tabla por cada camino en el árbol de herencia. De este modo, podemos considerar que aplicamos el patrón "un árbol de herencia, una tabla" a cada camino de herencia. Escuela Superior de Informática Universidad de Castilla-La Mancha Macario Polo Usaola 3 Apliquemos este patrón al árbol que tiene como raíz a la clase "Personas": en él identificamos seis caminos: • Persona-empleado-administrativo • Persona-empleado-conductor • Persona-empleado-profesor • Persona-alumno-ciclo1 • Persona-alumno-ciclo2 Debemos crear, por tanto, seis tablas. El diagrama relacional quedaría así: Figura 6 En este ejemplo concreto, una desventaja importante sería el hecho de que, en el diagrama de clases de la Figura 1, se especifica que en un asignatura puede haber matriculados muchos alumnos, independientemente de que sean de primer o segundo ciclo. Con el diagrama de la Figura 6, tendríamos un problema de integridad referencial, ya que estaríamos exigiendo que todo alumno que aparezca en la tabla "Asignatura" esté presente también en las tablas "Ciclo1" y "Ciclo2". Nótese que en ninguno de los diagramas de las figuras anteriores teníamos este problema. Esto demuestra el hecho de que no tiene por qué utilizarse siempre el mismo patrón para todo el diagrama de clases: al árbol correspondiente a la clase Persona podemos aplicarle un patrón, y otro distinto al de Vehículos. Escuela Superior de Informática Universidad de Castilla-La Mancha Macario Polo Usaola 4 2 Patrones para la asignación de responsabilidades relacionadas con la persistencia En general, todas las clases persistentes deberán implementar de alguna manera los métodos necesarios para manipular sus instancias desde el punto de vista de la persistencia. Es decir, que deben contar con métodos que permitan: • Materializar instancias: construir objetos a partir de registros almacenados en la base de datos. • Insertar registros en la base de datos, a partir de una instancia. • Actualizar el valor de un registro correspondiente a un objeto. • Eliminar de la base de datos el registro correspondiente a la instancia. Típicamente, estos métodos se implementarán en forma de instrucciones Select, Insert, Update y Delete del lenguaje SQL, o bien mediante llamadas a procedimientos almacenados que realicen estas funciones. Existen varias políticas para realizar la asignación de estas responsabilidades, que se describen en forma de patrones. 2.1 Patrón "tablas como objetos" Mediante este patrón, cada clase es responsable de implementar sus métodos persistentes. Es decir, que podríamos reescribir la Figura 1 de este modo (Figura 7): Escuela Superior de Informática Universidad de Castilla-La Mancha Macario Polo Usaola 5 Figura 7 Como se observa, las superclases (Persona y Vehículo) y las clases que no heredan de ninguna otra (Viaje y Asignatura) definen las cuatro operaciones persistentes básicas (la operación "Materializar" será típicamente un constructor, que tomará tantos parámetros como columnas haya en su correspondiente tabla de la base de datos). Evidentemente, cada subclase debe redefinir las cuatro operaciones, ya que la instrucción SQL necesaria para insertar un Conductor no es la misma que la utilizada para insertar una Persona. El patrón utilizado para transformar el diagrama de clases al diagrama relacional afecta en gran medida a la implementación de las operaciones de persistencia: a) Si hemos utilizado el patrón "un árbol de herencia, una tabla" (Figura 5), el método para insertar en la base de datos un objeto de clase Coche sería: public void insert() { Escuela Superior de Informática Universidad de Castilla-La Mancha Macario Polo Usaola 6 String SQL="Insert into Vehículos (Matrícula, Marca, Potencia) values ('" + mMatricula + "', '" + mMarca + "', " + mPotencia + ")"; // Nótese que no insertamos valor en la columna "Toneladas", pq. corresponde a los camiones. /* y aquí, de alguna manera (ya veremos varias), ejecutar la instrucción */ } b) Si hemos usado el patrón "Una clase, una tabla" (Figura 2), tendremos que insertar dos registros: uno en la tabla Vehículos (para que no se viole la regla de integridad referencial) y otro en la tabla Coches: public void insert() { // Iniciar transacción, para garantizar que o se ejecutan las dos instrucciones o no se ejecuta ninguna. String SQL="Insert into Vehículos (Matrícula, Marca) values ('" + mMatricula + "', '" + mMarca + "')"; // Ejecutar instrucción anterior SQL="Insert into Coches (Matrícula, Potencia) values ('" + mMatricula + "', " + mPotencia + ")"; // Ejecutar instrucción // Finalizar transacción } 2.2 Patrón "Fabricación pura" Con este patrón se pretende aumentar la cohesión de las clases de la capa de Dominio, mediante la delegación de las operaciones persistentes a clases asociadas. De este modo, las clases de la capa de Dominio se responsabilizan únicamente de las operaciones relacionadas con el enunciado del problema. Lo que se hace es crear una clase "Fabricación pura" por cada clase de Dominio. Cuando una instancia de una clase de Dominio quiere insertarse, se lo dice (le pasa un mensaje) a su clase asociada. Escuela Superior de Informática Universidad de Castilla-La Mancha Macario Polo Usaola 7 Figura 8 Como puede intuirse a partir de la Figura 8, las clases de la capa de Dominio que forman parte del enunciado del problema (Conductor, Viaje, etc.) quedan más simples, más fáciles de leer, de comprender y se afectan menos por los cambios en la base de datos; sin embargo, el acoplamiento del sistema aumenta. En este caso, las clases de la capa de Dominio también deben tener métodos persistentes, pero ahora mucho más sencillos. Por ejemplo, para insertar un Coche, tendríamos lo siguiente: class Coche { // atributos de "dominio" (marca, etc.) FPCoche mFP; // métodos no persistentes public void insert() { mFP.insert(this); } } Escuela Superior de Informática Universidad de Castilla-La Mancha Macario Polo Usaola 8 2.3 Patrón "método-plantilla" Mediante este patrón, se declaran en una superclase todos los métodos relacionados con la persistencia, de la cual heredan todas las clases persistentes. La superclase dará implementación a todos los métodos comunes a las clases persistentes, mientras que declara como abstractas todas las operaciones cuya implementación depende de la subclase. Por ejemplo, tal vez todas las clases deban identificar al usuario actual ante la base de datos antes de realizar una operación persistente. Si la implementación de esta operación es común a todas las clases persistentes, entonces podría ser implementada en la superclase. El resto de operaciones, como insert, update y delete, serían declaradas como abstractas y tendrían que ser implementadas en cada clase persistente. Figura 9 2.4 Combinaciones de patrones Evidentemente, pueden utilizarse diferentes combinaciones de patrones de asignación de responsabilidades. Por ejemplo, pueden utilizarse "fabricaciones puras" que hereden de una clase "Método-plantilla"; o puede usarse el patrón "Fabricación Escuela Superior de Informática Universidad de Castilla-La Mancha Macario Polo Usaola 9 pura" para un fragmento del diagrama de clases, el "Tablas como objetos" para otro trozo, el "Método-plantilla" para otro y una combinación para el resto. Es importante resaltar que el patrón que se utilice para "traducir" el diagrama de clases al diagrama relacional tiene mucha influencia en la implementación de las operaciones persistentes. Escuela Superior de Informática Universidad de Castilla-La Mancha Macario Polo Usaola 10