Patrones de Diseño en Bases de Datos Orientadas a Objetos – Parte I

Los modelos de bases de datos tradicionales presentan algunas deficiencias cuando se trata de aplicaciones complejas o sofisticadas. Las bases de datos orientadas a objetos se crearon para tratar de satisfacer las necesidades de estas nuevas aplicaciones. Otro motivo para la creación de las bases de datos orientadas a objetos es el creciente uso de los lenguajes orientados a objetos para desarrollar aplicaciones.

Con el nacimiento de estas bases de datos orientadas a objetos surgieron problemas recurrentes que ya existían en el mundo de los objetos pero ahora enfocados en la persistencia. Se analizarán en el presente texto algunas soluciones a estos problemas; patrones específicos capaces de resolver estos problemas de diseño de los objetos.

 

  • Introducción

 

Las Bases de datos orientados a objetos se propusieron con la idea de satisfacer las necesidades de las aplicaciones más complejas. El enfoque orientado a objetos ofrece la flexibilidad para cumplir con algunos de estos requerimientos sin estar limitado por los tipos de datos y los lenguajes de consulta disponibles en los sistemas de bases de datos tradicionales. El objetivo de una base de datos O.O. es proveer la integración entre un lenguaje de programación orientado a objetos y el conjunto de características esperadas en un sistema de bases de datos.

Las bases de datos Orientadas a Objetos (de ahora en más BDOO), presentan grandes ventajas y diferencias respecto a las bases de datos relacionales; en esta oportunidad se estudiará y desarrollara el uso de patrones de diseño para las BDOO. Un patrón de diseño es una solución a un problema específico del diseño de BDOO. Nos ayudan a resolver problemas de diseño que ocurren repetidamente, y por ende esta basado en la reutilización del diseño de las BDOO. Los mismos representan soluciones que han sido desarrolladas y han ido evolucionando a lo largo del tiempo. A lo largo del texto estudiaremos algunos de los patrones mas utilizados, y presentaremos las ventajas y usos de los mismos.

  • Patrón de diseño Proxy (Surrogate).

 

El primer patrón para analizar es el denominado Proxy, también conocido como Surrogate (sustituto).

Es un patrón muy útil cuando se desea evitar o proteger el acceso a uno o varios objetos cuando la lógica o complejidad de las operaciones de los objetos reales varían. Se usa cuando se necesita una referencia a un objeto más flexible o sofisticada que un puntero.

Es un patrón estructural, debido a que nos indica cómo se organizan los  objetos en memoria. El propósito de este patrón es proporcionar un intermediario de un objeto para controlar su acceso. El intermediario (o subrogado) controla el acceso al objeto que estamos considerando.

El objeto que actúa de Proxy redirije, redirecciona, o invoca a los métodos del Objeto Real cuando sea necesario. Quien tiene el control real sobre los verdaderos objetos es el Proxy. Es decir que el Proxy se encarga de comunicarse y tomar las decisiones adecuadas para responder a las necesidades del cliente.

 

2.1 Ejemplo de uso:


Consideremos un editor que puede incluir objetos gráficos dentro de un documento. Se requiere que la apertura de un documento sea rápida, mientras que la creación de algunos objetos (imágenes de gran tamaño) es costosa, por lo que se debería evitar crear todos los objetos costosos a la vez en cuanto se abre el documento. Por otro lado, tampoco es necesario, ya que no todos esos objetos serán visibles en el documento al mismo tiempo. Interesa por tanto retrasar el coste de crear e inicializar un objeto hasta que es realmente necesario (por ejemplo, no abrir las imágenes de un documento hasta que no son visibles).

La solución que se plantea para ello es la de cargar las imágenes bajo demanda utilizando un objeto proxy. Dicho objeto se comporta como una imagen normal y es el responsable de cargar la imagen bajo demanda. El  proxy envía directamente la solicitud a la  imagen. Por lo tanto, debe mantener una referencia a la imagen después de crearla.

Vamos a suponer que las imágenes se almacenan en archivos separados. En este caso podemos utilizar el nombre del archivo como la referencia al objeto real. El Proxy también almacena su extención, es decir, su anchura y altura. La extención permite que el Proxy pueda responder a las preguntas sobre su tamaño que le haga el formateador, sin crear realmente la imagen.

El siguiente diagrama de clases ilustra el ejemplo con más detalles:

El editor de documentos accede a las imágenes insertadas a través de la interfaz definida por la clase de gráficas abstracta Graphic. ImageProxy es una clase para las imágenes que se crean en la demanda. ImageProxy mantiene el nombre del archivo como una referencia a la imagen en el disco. El nombre del archivo se pasa como argumento al constructorImageProxy.
ImageProxy también almacena el cuadro delimitador de la imagen y una referencia la instancia de la imagen real. Esta referencia no será válida hasta que el proxy no cree ducha imagen real. La operación Draw() se asegura de que la imagen ha sido creada antes de enviarle la petición. GetExtent redirige la petición a la imagen solo si ésta ha sido creada, de lo contrario ImageProxy devuelve su extención.

 

2.2 Aplicabilidad


 Este patrón es aplicable cada vez que hay necesidad de una referencia a un objeto más versátil que un simple puntero. Éstas son varias situaciones comunes en las que es aplicable el patrón Proxy:

 

  1. Un Proxy remoto proporciona un representante local de un objeto situado en otro espacio de direcciones. NEXTSTEP [Add94] usa la clase NXProxy con ese propósito.
  2. Un Proxy virtual crea objetos costosos por encargo. El ImageProxy descrito anteriormente, es un ejemplo de este tipo de Proxy.
  3. Un Proxy de protección controla el acceso al objeto original. Los Proxies de protección son útiles cuando los objetos deberían tener diferentes permisos de acceso. Por ejemplo, los KernelProxy del sistema operativo Choices, proporcionan un acceso protegido a los objetos del sistema operativo.
  4. Una Referencia Inteligente es un sustituto de un simple puntero que lleva a cabo operaciones adicionales cuando se accede a un objeto. Algunos ejemplos de usos típicos son:

– contar el número de referencias al objeto real,         de manera que este pueda liberarse automáticamente cuando no haya ninguna referencia apuntandole   (punteros inteligentes).

– cargar un objeto persistente en la memoria cuando es referenciado por primera vez.

–  Comprobar que se bloquea el objeto real antes de acceder a el para garantizar que no pueda ser modificado por ningún otro objeto.

2.3 Estructura


2.4 Participantes


 

  • Proxy (ImageProxy)
    • Mantiene una referencia que permite al Proxy acceder al objeto real. El Proxy puede referirse a un sujeto en caso de que las interfaces de SujetoReal y Sujeto sean la misma.
    • Proporciona una interfaz identica a la de Sujeto, de manera que un Proxy pueda ser sustituido por el sujeto real.
    • Controla el acceso al sujeto real, y puede ser responsable de su creación y borrado.
    • Otras responsailidades dependen del tipo de Proxy.
      • Los proxies remotos son responsables de codificar una petición y sus argumentos para enviar la petición codificada al sujeto real que se encuentra en un espacio de direcciones diferentes.
      • Los proxies virtuales pueden guardar información adicional sobre el sujeto real, por lo que pueden retardar el acceso al mismo. Por ejemplo, el ImageProxy de la sección de ejemplo, guarda la extención de la imagen real.
      • Los proxies de protección comprueban que el llamador tenga los permisos de accesos necesarios para realizar una petición.

 

  • Sujeto (Graphic)
    • Define la interfaz común para el SujetoReal y el Proxy, de modo que pueda usarse un Proxy en cualquier sitio en el que se espera un SujetoReal.

 

  • SujetoReal (Image)
    • Define el objeto real representado.

 

2.5 Colaboraciones


 

El Proxy redirige peticiones al SujetoReal cuando sea necesario, dependiendo del tipo de Proxy.

 

2.6 Consecuencias


 

El patrón Proxy introduce un nivel de indirección al acceder a un objeto. Esta indirección adicional tiene muchos posibles usos, dependiendo del tipo de Proxy:

 

  1. Un Proxy remoto puede ocultar el hecho de que un objeto recide en un espacio de direcciones diferente
  2. un Proxy virtual puede llevar a cabo optimizaciones tales como crear un objeto por encargo.
  3. tanto los proxies de protección, como las referencias inteligentes, permiten realizar tareas de mantenimiento adicionales cuando se accede a un objeto.

 

Hay otra optimización que el patrón Proxy puede ocultar al cliente, se denomina copia-de-escritura, y esta relacionada con la creación por encargo. Copiar un objeto grande y complejo puede ser muy costoso. Si esa copia no se modifica nunca, no es necesario invertir en ese gasto. Utilizando un Proxy para posponer la copia nos aseguramos de pagar solamente el precio de copiar el objeto en caso de que este se modifique.

Para realizar una copia-de-escritura el sujeto debe tener un contador de referencias. Copiar el Proxy no será mas que incrementar este contador. Sólo cuando el cliente solicite una operación que modifica el sujeto es cuando el Proxy realmente lo copia. En ese caso el Proxy también tiene que disminuir el contador de referencia al sujeto. Cuando el contador llega a 0, se borra el sujeto.

La copia-de-escritura puede reducir significativamente el coste de copiar sujetos pesados.



Seguimos con más patrones la próxima.

Dejá un comentario