Programación en Ada/Tipos abstractos de datos
Tipos abstractos de datos (tipos privados)
editarUna 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:
package
Números_complejosis
type
TComplejois
record
Real, Imag: Float;end
record
; I:constant
TComplejo := (0.0, 1.0);function
"+" (X, Y: TComplejo)return
TComplejo;function
"-" (X, Y: TComplejo)return
TComplejo;function
"*" (X, Y: TComplejo)return
TComplejo;function
"/" (X, Y: TComplejo)return
TComplejo;end
Nú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
:
package
Números_complejosis
-- Parte visible.
type
TComplejois
private
;-- Tipo privado.
I:constant
TComplejo;-- No se puede asignar valor todavía.
function
"+" (X, Y: TComplejo)return
TComplejo;function
"-" (X, Y: TComplejo)return
TComplejo;function
"*" (X, Y: TComplejo)return
TComplejo;function
"/" (X, Y: TComplejo)return
TComplejo;function
Construir_complejo (R, I: Float)return
TComplejo;function
Parte_imaginaria (X: TComplejo)return
Float;function
Parte_real (X: TComplejo)return
Float;private
-- Parte oculta.
type
TComplejois
record
Real, Imag: Float;end
record
; I:constant
TComplejo := (0.0, 1.0);end
Nú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:
package
body
Números_complejosis
function
"+" (X, Y: Tcomplejo)return
TComplejois
begin
return
(X.Real + Y.Real, X.Imag + Y.Imag);end
"+";-- ... "-", "* y "/" similarmente.
function
Construir_complejo (R, I: Float)return
TComplejois
begin
return
(R, I);end
Construir_complejo;function
Parte_real (X: TComplejo)return
Floatis
begin
return
X.Real;end
Parte_real;-- ... Parte_imaginaria análogamente.
end
Números_complejos;
Y podría ser utilizado transparentemente, por ejemplo, dentro de un bloque como:
declare
use
Números_complejos; C1, C2: TComplejo; R1, R2: Float;begin
C1 := 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:
-- ...
private
Pi:constant
:= 3.1416;type
TComplejois
record
R: Float; Theta: Floatrange
0.0 .. 2*Pi;end
recod; I:constant
TComplejo := (1.0, 0.5*Pi);end
Números_complejos;
Lo único que se necesitaría sería reescribir el cuerpo del paquete y recompilarlo.