4. El modelo estándar ODMG
Un grupo de representantes de la industria de las bases de datos formaron el ODMG (Object Database Management Group) con el propósito de definir estándares para los SGBD orientados a objetos. Este grupo propuso un modelo estándar para la semántica de los objetos de una base de datos. Su ´ultima versión, ODMG 3.0, apareció en enero de 2000. Los principales componentes de la arquitectura ODMG para un SGBD orientado a objetos son los siguientes: Modelo de objetos.
Lenguaje de definición de objetos (ODL).
Lenguaje de consulta de objetos (OQL).
Conexión con los lenguajes C++, Smalltalk y Java.
4.1. Modelo de objetos
El modelo de objetos ODMG permite que tanto los diseños, como las implementaciones, sean portables entre los sistemas que lo soportan. Dispone de las siguientes primitivas de modelado:
Los componentes básicos de una base de datos orientada a objetos son los objetos y los literales. Un objeto es una instancia autocontenida de una entidad de interés del mundo real. Los objetos tienen algún tipo de identificador ´único. Un literal es un valor específico, como “Amparo” o 36. Los literales no tienen identificadores. Un literal no tiene que ser necesariamente un solo valor, puede ser una estructura o un conjunto de valores relacionados que se guardan bajo un solo nombre.
Los objetos y los literales se categorizan en tipos. Cada tipo tiene un dominio específico compartido por todos los objetos y literales de ese tipo. Los tipos también pueden tener comportamientos. Cuando un tipo tiene comportamientos, todos los objetos de ese tipo comparten los mismos comportamientos. En el sentido practico, un tipo puede ser una clase de la que se crea un objeto, una interface o un tipo de datos para un literal (por ejemplo, integer). Un objeto se puede pensar como una instancia de un tipo.
Lo que un objeto sabe hacer son sus operaciones. Cada operación puede requerir datos de entrada (parámetros de entrada) y puede devolver algún valor de un tipo conocido.
Los objetos tienen propiedades, que incluyen sus atributos y las relaciones que tienen con otros objetos. El estado actual de un objeto viene dado por los valores actuales de sus propiedades. Una base de datos es un conjunto de objetos almacenados que se gestionan de modo que puedan ser accedidos por múltiples usuarios y aplicaciones.
La definición de una base de datos esta contenida en un esquema que se ha creado mediante el lenguaje de definición de objetos ODL (Object Definition Language) que es el lenguaje de manejo de datos que se ha definido como parte del estándar propuesto para las bases de datos orientadas a objetos.
4.1.1. Objetos
Los tipos de objetos se descomponen en atómicos, colecciones y tipos estructurados.
Los tipos colección, que se derivan de la interface Collection, son la propuesta del estándar para las clases contenedor. Los objetos colección identificados por el estándar son los siguientes:
Set<tipo>: es un grupo desordenado de objetos del mismo tipo. No se permiten duplicados.
Bag<tipo>: es un grupo desordenado de objetos del mismo tipo. Se permiten duplicados.
List<tipo>: es un grupo ordenado de objetos del mismo tipo. Se permiten duplicados.
Array<tipo> : es un grupo ordenado de objetos del mismo tipo que se pueden acceder por su posición. Su tamaño es dinámico y los elementos se pueden insertar y borrar de cualquier posición.
Dictionary<clave,valor> : es como un ´índice. Esta formado por claves ordenadas, cada una de ellas emparejada con un solo valor.
Los tipos estructurados son los siguientes:
Date : es una fecha del calendario (día, mes y año).
Time : es una hora (hora, minutos y segundos).
Timestamp : es una hora de una fecha (con precisión de microsegundos).
Interval : es un período de tiempo.
Estos tipos tienen la misma definición que los tipos con el mismo nombre del estándar de
SLQ.
Los objetos se crean utilizando el método new(). Además, todos heredan la interface que se muestra a continuación: interface Object f enum Lock Typefread,write,upgradeg;
void lock(in Lock Type mode) raises(Lock Not Granted?);
boolean try lock(in Lock Type mode);
boolean same as(in Object anObject);
Object copy();
void delete();
g;
Cada objeto tiene un identificador de objeto ´único generado por el SGBD, que no cambia y que no se reutiliza cuando el objeto se borra. Cada SGBD genera los identificadores siguiendo sus propios criterios.
Los objetos pueden ser transitorios o persistentes. Los objetos transitorios existen mientras vive el programa de aplicación que los ha creado. Estos objetos se usan tanto como almacenamiento temporal como para dar apoyo al programa de aplicación que se esta ejecutando.
Los objetos persistentes son aquellos que se almacenan en la base de datos.
4.1.2. Literales
Los tipos literales se descomponen en atómicos, colecciones, estructurados o nulos. Los literales no tienen identificadores y no pueden aparecer solos como objetos, sino que están embebidos en objetos y no pueden referenciarse de modo individual. Los literales atómicos son los siguientes:
boolean : un valor que es verdadero o falso.
short : un entero con signo, normalmente de 8 o 16 bits.
long : un entero con signo, normalmente de 32 o 64 bits.
unsigned short : un entero sin signo, normalmente de 8 o 16 bits.
unsigned long : un entero sin signo, normalmente de 32 o 64 bits.
float : un valor real en coma flotante de simple precisión.
double : un valor real en coma flotante de doble precisión.
octet : un almacén de 8 bits.
char : un carácter ASCII o UNICODE.
string : una cadena de caracteres.
enum : un tipo enumerado donde los valores se especifican explícitamente cuando se declara el tipo.
Los literales estructurados contienen un número fijo de elementos heterogéneos. Cada elemento es un par <nombre, valor> donde valor puede ser cualquier tipo literal. Los tipos estructurados son: date, time, timestamp, interval y struct. Y los tipos colección son: set<tipo>, bag<tipo>, list<tipo>, array<tipo> y dictionary<clave,valor>.
4.1.3. Tipos
Una de las características más importantes del paradigma orientado a objetos es la distinción entre la interface pública de una clase y sus elementos privados (encapsulación).
El estándar propuesto hace esta distinción hablando de la especificación externa de un tipo y de sus implementaciones.
Una interface es una especificación del comportamiento abstracto de un tipo de objeto y contiene las signaturas de las operaciones. Aunque una interface puede tener propiedades (atributos y relaciones) como parte de su especificación, ´estas no pueden ser heredadas desde la interface. Además, una interface no es instanciadle por lo que no se pueden crear objetos a partir de ella (es el equivalente de una clase abstracta en la mayoría de los lenguajes de programación).
Una clase es una especificación del comportamiento abstracto y del estado abstracto de un tipo de objeto. Las clases son instanciadles, por lo que a partir de ellas se pueden crear instancias de objetos individuales (es el equivalente a una clase concreta en los lenguajes de programación).
El estándar propuesto soporta la herencia simple y la herencia múltiple mediante las interfaces. Ya que las interfaces no son instanciadles, se suelen utilizar para especificar operaciones abstractas que pueden ser heredadas por clases o por otras interfaces. A esto se le denomina herencia de comportamiento y se especifica mediante el símbolo “:”. La herencia de comportamiento requiere que el súpertipo sea una interface, mientras que el subtipo puede ser una clase o una interface.
La herencia es una relación “es un”: interface Articulo Venta? …; interface Mueble : Articulo Venta …;
class Silla : Mueble …;
class Mesa : Mueble …;
class Sof¶a : Mueble …;
La interface o clase más baja de la jerarquía es el tipo más específico. Ya que hereda los comportamientos de todos los tipos que tiene por encima en la jerarquía, es la interface o clase más completa. En el ejemplo anterior, los tipos más específicos son Silla, Mesa y Sof¶a.
Uno de los beneficios prácticos de la herencia es que se puede hacer referencia a los subtipos como su súpertipo. Por ejemplo, un programa de aplicación puede hacer referencia a sillas, mesas y sofás como muebles o incluso como artículos de venta. Esto hace que sea más sencillo tratar los subtipos como un grupo cuando sea necesario.
Los subtipos se pueden especializar como sea necesario añadiéndoles comportamientos.
Los subtipos de un subtipo especializado heredan también los comportamientos añadidos.
El modelo orientado a objetos utiliza la relación extiende (extends) para indicar la herencia de estado y de comportamiento. En este tipo de herencia tanto el subtipo como el súpertipo deben ser clases. Las clases que extienden a otra clase ganan acceso a todos los estados y comportamientos del súpertipo, incluyendo cualquier cosa que el súpertipo haya adquirido a través de la herencia de otras interfaces. Una clase puede extender, como máximo, a otra clase. Sin embargo, si se construye una jerarquía de extensiones, las clases de más abajo en la jerarquía heredan todo lo que sus s´upertipos heredan de las clases que tienen por encima.
El modelo permite al diseñador que declare una extensión (extent) para cada tipo de objeto definido como una clase. La extensión de un tipo tiene un nombre e incluye todas las instancias de objetos persistentes creadas a partir de dicho tipo. Declarar una extensión denominada empleados para el tipo de objeto Empleado es similar a crear un objeto de tipo Set<Empleado> denominado empleados. Una extensión se puede indexar para que el acceso a su contenido sea más rápido.
Una clase con una extensión puede tener una o más claves (key). Una clave es un identificador ´único. Cuando una clave esta formada por una sola propiedad, es una clave simple; si esta formada por varias propiedades, es una clave compuesta. A diferencia del modelo relacional, las claves ´únicas no son un requisito.
Una implementación de un tipo consta de dos partes: la representación y los métodos.
La representación es una estructura de datos dependiente de un lenguaje de programación que contiene las propiedades del tipo. Las especificaciones de la implementación vienen de una conexión con un lenguaje (Language binding). Esto quiere decir que la representación interna de un tipo será diferente dependiendo del lenguaje de programación que se utilice y que un mismo tipo puede tener más de una representación.
Los detalles de las operaciones de un tipo se especifican mediante un conjunto de métodos.
En la especificación externa de cada operación debe haber al menos un método. Sin embargo, un tipo puede incluir métodos que nunca se ven desde fuera del tipo. Estos métodos son los que realizan algunas funciones necesarias para otros métodos del tipo.
Los métodos se escribirán en el mismo lenguaje de programación utilizado para expresar la representación del tipo. Si una base de datos soporta aplicaciones programadas en C++, Java y Smalltalk, entonces será necesario tener tres implementaciones para cada tipo, una para cada lenguaje, aunque cada programa de aplicación utilizará sólo la implementación que le corresponda.
4.1.4. Propiedades
El modelo de objetos ODMG define dos tipos de propiedades: atributos y relaciones. Un atributo se define del tipo de un objeto. Un atributo no es un objeto de “primera clase”, por lo tanto no tiene identificador, pero toma como valor un literal o el identificador de un objeto.
Las relaciones se definen entre tipos. El modelo actual sólo soporta relaciones binarias con cardinalidad 1:1, 1:n y n:m. Una relación no tiene nombre y tampoco es un objeto de “primera clase”, pero define caminos transversales en la interface de cada dirección. En el lado del muchos de la relación, los objetos pueden estar desordenados (set o bag) u ordenados (list). La integridad de las relaciones la mantiene automáticamente el SGBD y se genera una excepción cuando se intenta atravesar una relación en la que uno de los objetos participantes se ha borrado. El modelo aporta operaciones para formar (form) y eliminar (drop) miembros de una relación.
4.1.5. Transacciones
El modelo estándar soporta el concepto de transacciones, que son unidades lógicas de trabajo que llevan a la base de datos de un estado consistente a otro estado consistente. El modelo asume una secuencia lineal de transacciones que se ejecutan de modo controlado. La concurrencia se basa en bloqueos estándar de lectura/escritura con un protocolo pesimista de control de concurrencia. Todos los accesos, creación, modificación y borrado de objetos persistentes se deben realizar dentro de una transacción. El modelo especifica operaciones para iniciar, terminar (commit) y abortar transacciones, así como la operación de checkpoint.
Esta ´ultima operación hace permanentes los cambios realizados por la transacción en curso sin liberar ninguno de los bloqueos adquiridos.