Las restricciones textuales que hay que añadir son las siguientes:
No puede haber dos instancias de ProgresoMedio asociadas a las mismas instancias de Ordinaria y Generación.
No puede haber dos instancias de ProgresoMI asociadas a las mismas instancias de
Ordinaria y Generación.
Además de lo explicado, cabe decir que para ejecutar el algoritmo de programación genética, que se encuentra en la clase Ordinaria, se han realizado algunas modificaciones a la clase en la que se encuentra con el fin de aumentar su eficiencia y reducir su tiempo de ejecución. Las más importantes son las siguientes:
Las instancias de Individuo involucradas en el algoritmo se guardan en un vector (en el que los objetos se encuentran en posiciones consecutivas de memoria) dentro de la misma clase, en lugar de tener un vector de punteros a los objetos, tal como se haría normalmente en un lenguaje orientado a objetos.
Lo mismo se ha hecho con todas las instancias de Registro utilizadas en las etapas de entrenamiento y validación, las cuales se copian a un vector dentro de la clase. Ade-más, cada posición de este vector no contendrá los datos que hay en una instancia de Registro en el mismo formato, sino que se guardarán ocupando en mínimo espacio po-sible y con un formato específico para poder ser usados eficientemente por el algorit-mo. Esto se consigue guardando cada dato con un tipo simple de datos de la siguiente forma:
o fecha: Utiliza el tipo unsigned int, y su contenido representa a una fecha en formato AAAAMMDD. De esta forma, comparar fechas resulta inmediato. o apertura, máximo, mínimo, cierre, cierre_ajustado: Utiliza el tipo int, y
repre-sentan a un número en coma fija con 16 bits en la parte decimal, que es sufi-ciente para representar precios con la precisión correcta. Además, estos pre-cios ya se encuentran normalizados con la media de los 250 días anteriores, con lo cual el algoritmo tiene los datos en el formato adecuado.
La estructura que permite escoger a los individuos, comentada en el apartado 4.2.4.1, es un atributo de la clase. No se muestra en el diagrama de clases para no dificultar la comprensión del sistema desde el punto de vista de la ingeniería del software, ya que únicamente es utilizada por el algoritmo.
6.1.3 Capa de gestión de datos
La capa de gestión de datos permite obtener y modificar datos almacenados de manera persis-tente, así como guardar nuevos datos. Esta capa interacciona directamente con el Sistema Gestor de la Base de Datos (SGBD) para poder llevar a cabo sus acciones. Por ello, la capa debe utilizar el lenguaje del SGBD (variante SQL que utiliza, si es que utiliza este lenguaje) para po-der interactuar con él.
Para diseñar la capa de gestión de datos es necesario decidir cómo se guardarán en la base de datos los objetos resultantes del diagrama de clases de la capa de dominio y la estructura de la
101
base de datos. Siguiendo de forma estricta la teoría, cada objeto debería tener su tabla corres-pondiente en la base de datos. No obstante, el sistema construido para este proyecto no cons-ta con un gran número de clases, lo cual permite relajar este concepto en algunas ocasiones, explicadas a lo largo de este apartado.
Las clases singleton, Sesión, Periodo y Controlador, no se guardan en la base de datos, ya que siempre que se carga el programa sus atributos contienen los mismos valores porque se en-cuentran fijados en el código.
Los objetos Datos, Índice, Valor y Registro cuentan cada uno de ellos con una tabla. El objeto Ordinaria no se guarda, ya que es un contenedor temporal para ejecutar el algoritmo de pro-gramación genética y no tiene sentido conservar los datos específicos usados en la ejecución. Los datos relevantes de este objeto ya son guardados por el objeto Elite que lo posee.
Las poblaciones se guardan en dos tablas diferentes, según sean Elite o Personalizada. Cada una de estas dos tablas cuenta, además de los atributos propios de la clase, con los atributos de las clases de las que hereda. Este método, consistente en guardar cada clase concreta en una tabla distinta y no hacer lo mismo con las clases abstractas, se conoce como Concrete Ta-ble Inheritance. La tabla que guarda los objetos Elite, tiene una relación con los objetos Indivi-duo de la asociación “mejor_ind” de todos los objetos Ordinaria que tiene en la asociación “resultado”. Esto es así porque, como se ha comentado, los objetos Ordinaria no se guardan; solo se conserva la información relevante de éstos.
Cada objeto Individuo tiene una tabla, y, si es de tipo Seleccionado, también estará presente en otra tabla cuya clave primaria es la misma que en la primera tabla. La tabla de los objetos Se-leccionado guarda las estadísticas de la población con la que fue generado el individuo, ya que es posible borrar la tabla que las conserva (donde se guardan los objetos Elite) sin borrar el objeto Seleccionado, e interesa mantener estos datos.
Una modificación importante es la realizada al guardar el historial de un individuo durante su generación, cuyos objetos en el diagrama del dominio son: ProgresoMedio, ProgresoMI y Ge-neración. En la base de datos existe una tabla para los tres objetos, llamada historial-individuo. Además, al no haber ninguna tabla que guarde objetos Ordinaria, la tabla anterior esta rela-cionada con el objeto Individuo de su asociación “mejor_ind”. Hay que tener en cuenta tam-bién que en la base de datos no se guarda ningún objeto Individuo que no pertenezca o haya pertenecido a una asociación “mejor_ind” de un objeto Ordinaria.
Los objetos Nodo se guardan en la misma tabla en la que se guarda el objeto Individuo del que forman parte. Un objeto Nodo debe pertenecer a un solo Individuo y no tendría sentido de otra forma, por ello es correcto hacerlo así. La razón de esta modificación es que, hay una gran cantidad de objetos Nodo que componen un objeto Individuo. Si se utilizase una tabla para los objetos Nodo, se provocaría que en la base de datos fuese sencillo alcanzar un número de en-tradas en esta tabla muy elevado, lo que introduciría un overhead importante al guardar los datos, tanto en tiempo como en espacio de disco, y al recuperarlos. Hay que tener en cuenta que habría que introducir un identificador para cada Nodo y un atributo que guarde el objeto
102
Individuo al que pertenece, lo cual aumentaría aún más el espacio requerido y el tiempo de inserción al tener que mantener claves foráneas.
El formato en el que se guarda un objeto Nodo en uno Individuo se muestra en la siguiente figura. Todos los objetos Nodo que pertenecen a un objeto Individuo se guardan en un mismo campo binario de este último, de forma consecutiva y con dos bytes al principio del campo que indican cuántos bytes tiene el campo (estos dos bytes del principio quedan excluidos de la cuenta):
#bytes nodo 1 nodo 2 . . . nodo N
tipo
nodo valor
nodo:
2 bytes 4 bytes
2 bytes 6 bytes 6 bytes 6 bytes