Programación en Ada/Tipos abstractos de datos
Tipos abstractos de datos (tipos privados)
[editar]Una de las principales contribuciones de los lenguajes de alto nivel es que el programador no tiene que preocuparse de cómo se representan físicamente los datos en el computador. De esta idea surge el concepto de tipo de datos. Una extensión del mismo es el tipo abstracto de datos. Su implementación es de nuevo desconocida para el programador, esta vez no porque desconozca la arquitectura del computador subyacente, sino porque es encapsulado en un módulo que no permite el acceso directo a los detalles de su implementación. En su lugar, se proporciona al programador operaciones sobre el tipo que son invocaciones a entradas del módulo que lo encapsula.
Por ejemplo, consideremos la utilización de un tipo abstracto de datos que represente a un número complejo:
packageNúmeros_complejosistypeTComplejoisrecordReal, Imag: Float;endrecord; I:constantTComplejo := (0.0, 1.0);function"+" (X, Y: TComplejo)returnTComplejo;function"-" (X, Y: TComplejo)returnTComplejo;function"*" (X, Y: TComplejo)returnTComplejo;function"/" (X, Y: TComplejo)returnTComplejo;endNúmeros_complejos;
De este modo, el usuario debe conocer los detalles de la implementación y sabe que se utiliza una representación cartesiana. Además, el usuario está obligado a hacer uso de la representación.
Para impedir el uso del conocimiento de la representación con vistas,
por ejemplo, a poder cambiar ésta posteriormente, se puede hacer uso de
los tipos privados definiéndolos mediante la palabra reservada private:
packageNúmeros_complejosis-- Parte visible.typeTComplejoisprivate;-- Tipo privado.I:constantTComplejo;-- No se puede asignar valor todavía.function"+" (X, Y: TComplejo)returnTComplejo;function"-" (X, Y: TComplejo)returnTComplejo;function"*" (X, Y: TComplejo)returnTComplejo;function"/" (X, Y: TComplejo)returnTComplejo;functionConstruir_complejo (R, I: Float)returnTComplejo;functionParte_imaginaria (X: TComplejo)returnFloat;functionParte_real (X: TComplejo)returnFloat;private-- Parte oculta.typeTComplejoisrecordReal, Imag: Float;endrecord; I:constantTComplejo := (0.0, 1.0);endNúmeros_complejos;
Ahora, se ha definido TComplejo como tipo privado y se resguardan los
detalles de su implementación en la parte no visible del paquete después
de la palabra reservada private y hasta el fin de la especificación del
paquete. En la parte visible (desde el comienzo de la especificación
hasta private), se da la información disponible fuera del paquete.
Las únicas operaciones disponibles son la asignación, la igualdad y la desigualdad, aparte de las añadidas en el paquete.
Nótese que el valor de I no se puede dar pues no se conocen todavía los detalles de la implementación, se declara como constante y se le asigna después un valor en la parte privada.
Las funciones Construir_complejo, Parte_imaginaria y Parte_real son ahora necesarias pues el usuario ya no conoce la estructura del tipo TComplejo y se necesita realizar dicha interfaz para poder manejar objetos del tipo privado.
El cuerpo se podría implementar de la siguiente manera:
packagebodyNúmeros_complejosisfunction"+" (X, Y: Tcomplejo)returnTComplejoisbeginreturn(X.Real + Y.Real, X.Imag + Y.Imag);end"+";-- ... "-", "* y "/" similarmente.functionConstruir_complejo (R, I: Float)returnTComplejoisbeginreturn(R, I);endConstruir_complejo;functionParte_real (X: TComplejo)returnFloatisbeginreturnX.Real;endParte_real;-- ... Parte_imaginaria análogamente.endNúmeros_complejos;
Y podría ser utilizado transparentemente, por ejemplo, dentro de un bloque como:
declareuseNúmeros_complejos; C1, C2: TComplejo; R1, R2: Float;beginC1 := Construir_complejo (1.5, -6.0); C2 := C1 + I; R := Parte_real (C2) + 8.0;end;
Si ahora se quisiera cambiar la implementación del tipo TComplejo y representarlo en forma polar, no sería necesario cambiar la parte visible de la especificación, por lo que todas las unidades que utilicen dicho paquete no tienen la necesidad de actualizarse. La interfaz exportada no ha cambiado y, por tanto, los programas que la utilizarán pueden seguir haciéndolo. Por ejemplo, ahora se podría representar en la parte privada de la especificación del paquete como:
-- ...privatePi:constant:= 3.1416;typeTComplejoisrecordR: Float; Theta: Floatrange0.0 .. 2*Pi;endrecod; I:constantTComplejo := (1.0, 0.5*Pi);endNúmeros_complejos;
Lo único que se necesitaría sería reescribir el cuerpo del paquete y recompilarlo.