You are on page 1of 7

Plp 3

Un ejemplo con estructuras de datos

Los programas usan estructuras de datos para almacenar informacin. Existen varias
estructuras de datos, por ejemplo listas, rboles, arreglos, o colas, para nombrar unos
pocos. Cada una de estas estructuras de datos pueden ser caracterizadas por su estructura y
sus mtodos de acceso.

Ejemplo:

Todos ustedes conocen las listas ligadas sencillas, las cules usan una estructura muy
simple, consistente en elementos que son empatados uno junto al otro

Las listas ligadas sencillas proveen solamente mtodos para aadir un elemento nuevo al
final y para suprimir el elemento del frente. Las estructuras de datos complejas pueden usar
estructuras ya existentes. Por ejemplo una cola puede ser estructurada como una lista ligada
sencilla. Sin embargo, las colas proveen mtodos de acceso para poner un elemento de
datos al final y para obtener el primer elemento de datos. (comportamiento first-in first-out
(FIFO), es decir, "primero-en-entrar-primero-en-salir")

Presentaremos ahora un ejemplo que usamos para presentar algunos conceptos de diseo.
Desde el momento que este ejemplo se usa solamente para ilustrar estos conceptos y
problemas, no es un ejemplo completo ni es el ptimo. Suponiendo que se quiera programar
una lista en un lenguaje de programacin modular tal como C o Modula-2. Como uno cree
que las listas pertenecen a una estructura de datos comn, decide implementarla en un
mdulo separado. Tpicamente, esto requiere que se escriban dos archivos: la definicin de
la interface y el archivo de implementacin. Usaremos un pseudo cdigo muy sencillo

/*
* Definicin de interface para un mdulo que implementa
* una lista ligada sencilla para almacenar datos de cualquier tipo.
*/

MODULE Singly-Linked-List-1

BOOL list_initialize();
BOOL list_append(ANY data);
BOOL list_delete();
list_end();

ANY list_getFirst();
ANY list_getNext();
BOOL list_isEmpty();

END Singly-Linked-List-1

Las definiciones de interfase solamente describen lo que est disponible pero no el cmo
sto se hace disponible. Se esconde la informacin de la implementacin en el archivo de

1
Plp 3

implementacin. Este es un principio fundamental en ingeniera de software, de modo que


repitmoslo: Se esconde la informacin de la implementacin real (ocultamiento de la
informacin). Esto permite cambiar la implementacin. Por ejemplo, para usar un algoritmo
ms rpido pero de ms consumo de memoria para almacenar elementos sin la necesidad de
cambiar otros mdulos de tu programa: Las llamadas a los procedimientos provistos
permanecen iguales.

La idea de esta interfase es la siguiente: Antes de usar la lista, uno debe llamar a
list_initialize() para inicializar las variables locales a dicho mdulo. Los siguientes dos
procedimientos implementan los mtodos de acceso mencionados append y delete. El
procedimiento append necesita una discusin ms detallada. La funcin list_append() lleva
un argumento data de tipo arbitrario. Esto es necesario desde el momento que desea usar su
lista en varios ambientes diferentes, por lo tanto, el tipo de los elementos de datos a ser
almacenados en la lista no es conocido de antemano. Por consecuencia, debe usar un tipo
de datos especial ANY el cul permite asignarle datos de cualquier tipo. El tercer
procedimiento list_end() necesita ser llamado cuando el programa termina con el fin de
permitirle al mdulo limpiar sus variables usadas internamente. Por ejemplo, se puede
desear liberar la memoria asignada.

Con los siguientes dos procedimientos list_getFirst() y list_getNext() se ofrece un


mecanismo simple para desplazarse a travs de la lista.

El desplazamiento puede hacerse usando el siguiente bucle:

ANY data;

data <- list_getFirst();


WHILE data IS VALID DO
doSomething(data);
data <- list_getNext();
END

Se tiene ahora un mdulo de lista que permite usar la lista con cualquier tipo de elemento
de datos. Pero, Qu sucede si se necesita ms de una lista en uno de los programas ?

Manejo de listas mltiples

Si se decide redisear el mdulo de lista para que sea capaz de manejar ms de una lista. Se
crea una nueva descripcin de interfase que incluya una definicin para un manejador de
lista. Este manejador se usa en cada procedimiento provisto para identificar en forma

2
Plp 3

unvoca la lista en cuestin. El archivo de definicin de interfase del nuevo mdulo de lista
tiene el siguiente aspecto:

/*
* Un mdulo de lista para ms de una lista.
*/

MODULE Singly-Linked-List-2
DECLARE TYPE list_handle_t;

list_handle_t list_create();
list_destroy(list_handle_t this);
BOOL list_append(list_handle_t this, ANY data);
ANY list_getFirst(list_handle_t this);
ANY list_getNext(list_handle_t this);
BOOL list_isEmpty(list_handle_t this);

END Singly-Linked-List-2;

Se usa DECLARE TYPE para introducir un nuevo tipo list_handle_t el cul representa tu
manejador de lista. No especificamos como este manejador est realmente representado o
an implementado. Tambin se esconde los detalles de la implementacin de este tipo de
datos en el archivo de implementacin. Ntese la diferencia con la versin anterior en la
cul solamente esconde funciones o procedimientos, respectivamente. Ahora, tambin
esconde la informacin de un tipo de datos definido por el usuario llamado list_handle_t.

Se usa list_create() para obtener un manejador a una nueva (y por lo mismo vaca) lista.
Cada uno de los otros procedimientos contiene el parmetro especial this el cul solamente
identifica la lista en cuestin. Todos los procedimientos operan ahora sobre este manejador
en lugar de operar sobre una lista global modular.

Podra decirse ahora, que se puede crear objetos lista. Cada uno de tales objetos puede ser
unvocamente identificado por su manejador y solamente se les pueden aplicar aquellos
mtodos que son definidos para operar sobre este manejador.

Problemas de la programacin modular

La seccin anterior muestra que ya hicimos programas con algunos conceptos de


orientacin a objetos en mente. Sin embargo, el ejemplo implica algunos problemas que
bosquejaremos enseguida.

Creacin y destruccin explcitas

En el ejemplo, cada vez que se quiere usar una lista, tiene que declarar explcitamente un
manejador y hacer una llamada a list_create() para obtener un manejador de lista vlido.

3
Plp 3

Despus del uso de la lista, debe llamar explcitamente a list_destroy() con el manejador de
la lista que quieres que se destruya. Si quieres usar una lista dentro de un procedimiento,
digamos, foo() , usas el siguiente esqueleto de cdigo:
PROCEDURE foo() BEGIN
list_handle_t myList;
myList <- list_create();

/* Do something with myList */


...

list_destroy(myList);
END

Comparemos la lista con otros tipos de datos, por ejemplo un entero. Los enteros se
declaran dentro de un mbito particular (por ejemplo, dentro de un procedimiento). Una vez
que los ha definido, puede usarlos. Una vez que abandona el mbito (el procedimiento
donde fue definido el entero, por ejemplo) el entero se pierde. Se crea y se destruye
automticamente. Algunos compiladores tambin inicializan los enteros recin creados con
un valor, tpicamente 0 (cero)

Cul es la diferencia con lo "objetos" tipo lista ? La vida de una lista tambin est definida
por su mbito, por lo tanto, debe crearse una vez que se entra al mbito y destruirse una vez
que se abandona. En el momento de su creacin, una lista debera inicializarse vaca. Por
consiguiente, nos gustara poder definir un lista en forma similar a la definicin de un
entero. Un esqueleto de cdigo para esto se vera del siguiente modo:
PROCEDURE foo() BEGIN
list_handle_t myList; /* La lista es creada e inicializada */

/* Hacer algo con myList */


...
END /* myList es destruda */

La ventaja estriba en que ahora el compilador se toma el cuidado de llamar en forma


apropiada los procedimientos de inicializacin y de finalizacin. Por ejemplo, esto asegura
que la lista sea correctamente eliminada, regresando los recursos al programa.

Datos y operaciones desacoplados

El desacoplamiento de datos y operaciones conduce usualmente a una estructura basada en


las operaciones en lugar de en los datos : Los Mdulos agrupan las operaciones comunes
(tales como aqullas operaciones list_...()) en forma conjunta. Entonces usa estas
operaciones proveyndoles explcitamente los datos sobre los cules deben operar. La
estructura de mdulo resultante est por lo tanto orientada a las operaciones ms que sobre
los datos. Se podra decir que las operaciones definidas especifican los datos que sern
usados.

4
Plp 3

En orientacin a objetos, la estructura se organiza por los datos. Uno escoge las
representaciones de datos que mejor se ajusten a tus requerimientos. Por consecuencia, sus
programas se estructuran por los datos ms que por las operaciones. As, esto es
exactamente del otro modo: Los datos especifican las operaciones vlidas. Ahora, los
mdulos agrupan representaciones de datos en forma conjunta.

Omisiones en la consistencia de datos

En nuestro ejemplo de la lista, tenemos que usar un tipo especial ANY para permitir a la
lista contener cualquier dato que gustemos.

sto implica que el compilador no puede garantizar la consistencia de los tipos de datos.

Considera el siguiente ejemplo que el compilador no puede chequear si es correcto:

PROCEDURE foo() BEGIN


SomeDataType data1;
SomeOtherType data2;
list_handle_t myList;

myList <- list_create();


list_append(myList, data1);
list_append(myList, data2); /* Oops */

...

list_destroy(myList);
END

Es su responsabilidad asegurarse que su lista sea usada consistentemente. Una posible


solucin es aadir informacin adicional acerca del tipo de datos a cada elemento de la
lista. Sin embargo, esto implica ms overhead y no salva de saber qu es lo que est
haciendo.

Lo que quisiramos tener es un mecanismo que nos permita especificar sobre que tipos de
datos debera ser definida la lista. La funcin total de la lista es siempre la misma, sin
importar si almacenamos manzanas, nmeros, autos o an listas. Por lo tanto, sera bueno
declarar una nueva lista con algo como esto :
list_handle_t<Apple> list1; /* una lista de manzanas */
list_handle_t<Car> list2; /* una lista de carros */

Las correspondientes rutinas de la lista deberan entonces regresar automticamente los


tipos correctos de datos. El compilador debera poder chequear la consistencia de los tipos.

5
Plp 3

Estrategias y representacin

El ejemplo de la lista implica operaciones para desplazarse a travs de la lista. Tpicamente,


se usa un cursor para ese propsito, el cul apunta al elemento actual. Esto implica una
estrategia de recorrido que define el orden en el que los elementos de la estructura de datos
sern visitados.

Para una estructura de datos simple como la lista sencilla ligada, uno puede pensar en
nicamente una estrategia de recorrido. Empezando con el elemento ms hacia la izquierda,
uno visita sucesivamente los vecinos de la derecha hasta que se alcanza el ltimo elemento.

Sin embargo, estructuras de datos ms complejas tales como los rboles, pueden ser
recorridos usando diferentes estrategias. Peor an, algunas veces las estrategias de recorrido
dependen del contexto particular en el que se usa la estructura de datos. Consecuentemente, tiene
sentido el separar la representacin o forma de la estructura de datos de su estrategia de recorrido.

Lo que hemos mostrado con la estrategia de recorrido se aplica a otras estrategias por igual.
Por ejemplo, la insercin de un elemento puede ser hecha de modo tal que se realice un
ordenamiento de elementos o se deje de hacer esto ltimo.

Desde los primeros tiempos de la programacin ha existido la necesidad de mejorar la


productividad de los programadores y de incrementar la reutilizacin del cdigo ya escrito.
Por ello, han ido surgiendo diferentes propuestas o metodologa sobre como escribir el
software. Algunas de esas filosofas han influido en sus sucesores. Es necesario, por tanto,
presentar estos paradigmas y su influencia en el diseo de la programacin orientada a
objetos en general.

As, en los primeros tiempos de los lenguajes de programacin de alto nivel all por los
aos setenta, el paradigma dominante era la Programacin Procedural. La idea bsica era
establecer los procedimientos, las funciones, que resolvan el problema, es decir, buscar los
algoritmos que resolvan el problema. El exponente clsico de este tipo de programas es
FORTRAN, si bien, PASCAL o C son tambin lenguajes que utilizar parte de esa filosofa.

Con el paso del tiempo los programas fueron creciendo y el ncleo de los programas paso a
ser los datos mas que los procedimientos. As surgi un nuevo paradigma denominado
Programacin Modular. Su principio es establecer mdulos que trabajen con los mismos
datos, de forma que <<escondan>> La complejidad del tratamiento de esos datos a otros
mdulos. La aportacin bsica de este paradigma a la programacin fue el concepto de
modulo, del que hacen uso por ejemplo, Modula-2 o el propio C a travs de las bibliotecas
de funciones.

El trabajo con estos mdulos especializados en un determinado tipo de datos hizo surgir
tambin la necesidad de estructurar esos tipos de datos. De esa forma, se dispona de
instrucciones para definir estructuras de datos, a travs de mecanismos como el struct de C
o el record de Pascal.

6
Plp 3

Por ejemplo, en C se puede crear un tipo de datos que represente a una persona de la
siguiente forma:

struct Persona {
Char nombre[15];
char apellidos[25];
int DNI[8]; }

Siguiendo con la programacin modular, a continuacin se creaba un modulo, un conjunto


de funciones en el caso de C, que gestionara las operaciones bsicas con ese tipo de datos.
Partiendo del ejemplo anterior, se podran definir funciones como:

Struct Persona Crear_Persona(char n[15],char a[25], int dni[8]);


int Copiar_Persona(struct persona origen, struct Persona destino);
int Borrar_Persona(struct Persona persona);
...

A esta conjuncin del tipo de datos con las funciones que lo manejan se le conoce como el
paradigma de la Abstraccin de Datos. C tambin soporta, como se acaba de ver, este
paradigma mediante las estructuras y las bibliotecas de funciones.

You might also like