next up previous
Siguiente: 4 Conceptos de Orientación a Objetos Arriba: Introducción a la Programación Orientada a Objetos Anterior: 2 Una Revisión a

Subsecciones

3 Tipos de Datos Abstractos

 
Peter Müller
Globewide Network Academy (GNA)
pmueller@uu-gna.mit.edu

Algunos autores describen la programación orientada a objetos como programación de tipos de datos abstractos y sus relaciones. Dentro de esta sección presentamos los tipos de datos abstractos como un concepto básico de orientación a objetos y exploramos conceptos usados en el ejemplo de la lista de la sección anterior con más detalle.

3.1 Manejando los Problemas

La primera cosa con la que uno se enfrenta cuando se escriben programas es el problema. Típicamente, tú te enfrentas a problemas "de la vida real" y te quieres facilitar la existencia por medio de un programa para dichos problemas. Sin embargo, los problemas de la vida real son nebulosos y la primera cosa que tienes que hacer es tratar de entender el problema para separar los detalles esenciales de los no esenciales : Tratas de obtener tu propia perspectiva abstracta, o modelo, del problema. Este proceso de modelado se llama abstracción y se ilustra en la Figura 3.1.


 
Figure 3.1:  Crear un modelo de un problema por abstracción.
\begin{figure}
{\centerline{
\psfig {file=FIGS/abstraction1.eps,width=4cm}
}}\end{figure}

El modelo define una perspectiva abstracta del problema. Esto implica que el modelo se enfoca solamente en aspectos relacionados con el problema y que tú tratas de definir propiedades del problema. Estas propiedades incluyen

por el problema.

Como ejemplo considera la administración de empleados en una institución. Tu superior viene y te pide que elabores un programa que permita administrar a los empleados. Bueno, ésto no es muy específico. Por ejemplo, ¿Qué información de los empleados necesita la administración ?, ¿Qué tareas deberían ser permitidas ? Los empleados son personas caracterizadas por muchas propiedades, unas pocas son :

Ciertamente que no todas estas propiedades son esenciales para resolver el problema de la administración. Solamente algunas de ellas son específicas del problema. En consecuencia, tu creas un modelo de un empleado para el problema. Este modelo solo implica propiedades que son necesarias para cumplir con los requerimientos de la administración, por ejemplo el nombre, fecha de nacimiento y el número social. A estas propiedades se les llama los datos del modelo (de empleado). Ahora ya se tienen descritas a las personas reales por medio de un empleado abstracto.

Desde luego, la pura descripción no es suficiente. Debe haber algunas operaciones definidas con las cuáles la administración sea capaz de manejar los empleados abstractos. Por ejemplo, debe haber una operación que te permita crear un empleado nuevo una vez que una persona ingrese a la institución. Consecuentemente, tienes que identificar las operaciones que deberían ser posibles de ser ejecutadas en un empleado abstracto. Decides también permitir el acceso a los datos del empleado solamente por medio de operaciones asociadas. Esto te permite asegurarte que los elementos de datos siempre estén en un estado apropiado. Por ejemplo, poder checar si una fecha provista es válida.

Para resumir, la abstracción es la estructuración de un problema nebuloso en entidades bien definidas por medio de la definición de sus datos y operaciones. Consecuentemente, estas entidades combinan datos y operaciones. No están desacoplados unos de otras.

3.2 Propiedades de los Tipos de Datos Abstractos

El ejemplo de la sección anterior muestra que por medio de la abstracción tu creas una entidad bien definida que puede ser adecuadamente manejada. Estas entidades definen la estructura de datos de un conjunto de elementos. Por ejemplo, cada empleado administrado tiene un nombre, fecha de nacimiento y número social.

La estructura de los datos puede ser accesada solamente por medio de operaciones definidas. Este conjunto de operaciones es llamada interface y es exportada por la entidad. Una entidad con las propiedades recién descritas se conoce como un tipo de datos abstracto (TDA).

La Figura 3.2 muestra un TDA que consiste en una estructura de datos abstracta y operaciones. Solamente las operaciones son visibles desde afuera y definen la interface.


 
Figura 3.2:  Un tipo de datos abstracto (TDA).
\begin{figure}
{\centerline{
\psfig {file=FIGS/abstraction2.eps,width=5cm}
}}\end{figure}

Una vez que un nuevo empleado es "creado", la estructura de datos es llenada con los valores reales : Ahora tú tienes una instancia de un empleado abstracto. Tú puedes crear tantas instancias de un empleado abstracto como sea necesario para describir cada una de las personas empleadas.

Tratemos de poner las características de un TDA en un modo más formal :

Definición (Tipo de Datos Abstracto) Un tipo de datos abstracto (TDA) se caracteriza por las siguientes propiedades :

1.
Exporta un tipo.
2.
Exporta un conjunto de operaciones. Este conjunto es llamado interface.
3.
Las operaciones de la interface son el único y exclusivo mecanismo de acceso a la estructura de datos del TDA.
4.
Axiomas y precondiciones definen el ámbito de aplicación del TDA.

Con la primera propiedad es posible crear más de una instancia de un TDA como se pudo ver con el ejemplo de la administración de empleados. Podrías recordar también el ejemplo de la lista del capítulo  2. En la primera versión hemos implementado una lista como un módulo y solo podíamos usar una lista a la vez. La segunda versión presenta un "manejador" como una referencia a un "objeto-lista". De lo que hemos aprendido ahora, el manejador en conjunción con las operaciones definidas en un módulo de lista, definen un TDA Lista:

1.
Cuando usamos el manejador definimos la correspondiente variable para que sea del tipo Lista.
2.
La interface para instancias del tipo Lista se define por medio del archivo de definición de la interface.
3.
Dado que el archivo de definicion de la interface no incluye la representación actual del manejador, éste no puede ser modificado directamente.
4.
El ámbito de aplicación está definido por el significado semántico de las operaciones provistas. Axiomas y precondiciones incluyen enunciados tales como

Sin embargo, todas estas propiedades son válidas solamente debido a nuestra comprensión y disciplina al usar el módulo de la lista. Es nuestra responsabilidad usar instancias de Lista de acuerdo a estas reglas.

Importancia del Encapsulamiento de la Estructura de los Datos

El principio de esconder la estructura de los datos usada y solamente proveer una bien definida interface se conoce como encapsulamiento. ¿Por qué es tan importante encapsular la estructura de los datos ?

Para contestar a esta pregunta, considera el siguiente ejemplo matemático donde queremos definir un TDA para números complejos. Para ésto, es suficiente saber que los números complejos constan de dos partes: la parte real y la parte imaginaria. Ambas partes están representadas por números reales. Los números complejos definen varias operaciones : suma, resta, multiplicación o división por nombrar algunas. Los axiomas y precondiciones son válidos tal y como están definidos por la definición matemática de los números complejos. Por ejemplo, existe un elemento neutral para la adición.

Para representar un número complejo es necesario definir la estructura de datos que va a ser usada por su TDA. Uno puede pensar en al menos dos posibilidades para hacer ésto :

El Punto 3 de la definición del TDA dice que para cada acceso a la estructura de los datos debe haber una operación definida. Los ejemplos de acceso de arriba parecen contradecir este requisito. ¿Es ésto realmente cierto ?

Veamos otra vez las dos posibilidades para representar números complejos. Pensemos únicamente en la parte real. En la primera versión, x es igual a c[0]. En la segunda versión, x es igual a c.r. En ambos casos x es igual a "algo". Es este "algo" el que difiere en la estructura de datos actual que se está usando. Pero en ambos casos, la operación ejecutada "igual a" tiene el mismo significado para declarar que x es igual a la parte real del número complejo c: ambos casos logran la misma semántica.

Si tú piensas en operaciones más complejas, el impacto de desacoplar esctructura de datos y operaciones se hace aún más evidente. Por ejemplo la suma de dos números complejos requiere que ejecutes una suma para cada parte. Por consecuencia, tú debes accesar el valor de cada parte, el cuál es diferente para cada versión. Al proveer una operación "suma" tu puedes encapsular estos detalles aparte de su uso actual. En el contexto de una aplicación tú simplemente "sumas dos números complejos" sin importar cómo se logra en la práctica esta funcionalidad.

Una vez que has creado un TDA para números complejos, digamos Complex, tu puedes usarlo de la misma manera que se usan los tipos de datos conocidos tales como los enteros (integers).

Resumamos ésto : La separación de las estructuras de los datos y las operaciones por una parte y la restricción de solamente accesar la estructura de los datos vía una bien definida interface por la otra, te permite escoger estructuras de datos apropiadas para el ambiente de la aplicación.

3.3 Tipos Genéricos de Datos Abstractos

Los TDAs se usan para definir un nuevo tipo a partir del cuál se pueden crear instancias. Como se mostró en el ejemplo de la lista, algunas veces estas instancias deberían operar del mismo modo sobre otros tipos de datos. Por ejemplo, uno puede pensar en listas de manzanas, carros o aún listas. La definición semántica de una lista siempre es la misma. Solamente el tipo de los elementos de datos cambia de acuerdo al tipo sobre el cuál debía operar la lista..

Esta información adicional podría ser especificada por un parámetro genérico que es especificado al momento de la creación de la instancia. Así, una instancia de un TDA genérico es en la práctica una instancia de una variante particular del TDA. Una lista de manzanas puede ser por lo tanto declarada como sigue :

    List<Apple> listOfApples;

Los corchetes angulares encierran ahora el tipo de datos para el cuál una variante del TDA genérico List sería creada. listOfApples ofrece la misma interface que cualquiera otra lista, pero opera en instancias del tipo Apple.

3.4 Notación

Debido a que los TDAs proveen una perspectiva abstracta para describir propiedades de conjuntos de entidades, su uso es independiente de un lenguaje de programación en particular. Presentamos aquí por lo tanto una notación que es adoptada de [3]. Toda descripción de un TDA consiste en dos partes :

Se presenta como ejemplo la descripción del TDA Integer. Sea k una expresión integer:

TDA Integer es
Datos

Una secuencia de dígitos que opcionalmente presentan como prefijo un signo más o un signo menos. Nos referimos a este número entero con signo como N.

Operaciones
constructor
Crea un nuevo integer.
add(k)
Crea un nuevo integer, suma de N y k.

Por consecuencia, la postcondición de esta operación es sum = N+k. ¡No confundir ésto con los enunciados de asignación tal como se usan en los lenguajes de programación ! Es más bien una ecuación matemática que da "verdadero" por cada valor sum, N y k después que add ha sido ejecutada.

sub(k)
Similar a add, esta operación crea un nuevo integer de la diferencia de ambos valores integer. Por lo tanto la postcondición para esta operación es sum = N-k.

set(k)
Pone a N lo que vale k. La postcondición para esta operación es N = k.

...
end

La descripción de arriba es una especificación para el TDA Integer. Nótese por favor, que usamos palabras para nombres de operaciones tales como "add". Podríamos haber usado el signo "+", que es más intuitivo, pero ésto podría llevar a alguna confusión : Tú debes distinguir la operación "+" de el uso matemático de "+" en la postcondición. El nombre de la operación es solamente sintaxis ahí donde la semántica se describe por las pre- y postcondiciones asociadas. Sin embargo, siempre constituye una buena idea el combinar ambos para hacer que la lectura de las especificaciones del TDA sea más fácil.

Los lenguajes de programación reales son libres de escoger una implementación arbitraria para un TDA. Por ejemplo, podrían implementar la operación add con el operador infijo "+" que condujera a una lectura más intuitiva para la suma de enteros.

3.5 Tipos de Datos Abstractos y Orientación a Objetos

Los TDAs permiten la creación de instancias con propiedades bien definidas y comportamiento bien definido. En orientación a objetos, nos referimos a los TDAs como clases. Por lo tanto, una clase define las propiedades de objetos instancia en un ambiente orientado a objetos.

Los TDAs definen la funcionalidad al poner especial énfasis en los datos involucrados, su estructura, operaciones, así como en axiomas y precondiciones. Consecuentemente, la programación orientada a objetos es "programación con TDAs" : al combinar la funcionalidad de distintos TDAs para resolver un problema. Por lo tanto, instancias (objetos) de TDAs (clases) son creados dinámicamente, usados y destruídos.

3.6 Ejercicios

 
1.
TDA Integer.
(a)
¿Por qué no hay precondiciones para las operaciones add y sub?
(b)
Obviamente, la descripción TDA de Integer está incompleta. Agrega los métodos mul, div y otros cualesquiera. Describe sus impactos especificando pre- y postcondiciones.
2.
Diseña un TDA Fraction que describa propiedades de las fracciones.
(a)
¿Qué estructuras de datos se pueden usar? ¿Cuáles son sus elementos?
(b)
¿Cuál es el aspecto de la interface?
(c)
Menciona unos cuantos axiomas y precondiciones.
3.
Describe con tus propias palabras las propiedades de tipos de datos abstractos.
4.
¿Por qué es necesario incluir axiomas y precondiciones a la definición de un tipo de datos abstracto?
5.
Describe con tus propias palabras la relación entre

next up previous
Siguiente: 4 Conceptos de Orientación a Objetos Arriba: Introducción a la Programación Orientada a Objetos Anterior : 2 Una Revisión a
P. Mueller
8/31/1997