18 octubre 2007

Implementando interfaces en Delphi (y III)

Una de las propiedades más interesantes que incorporan las interfaces es la de añadir un identificador único que la diferencie del resto.

IDENTIFICACION DE INTERFACES


Una interfaz puede tener un identificador unico a nivel global llamado GUID. Este identificador tiene la siguiente forma:

['{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}']

donde cada X es un dígito hexadecimal. Cada GUID es un valor binario de 16 bytes que hace que cada interfaz sea única. Los tipos TGUID y PGUID están declarados dentro de la unidad System del siguiente modo:

type
PGUID = ^TGUID;
TGUID = record
D1: Integer;
D2: Word;
D3: Word;
D4: array[0..7] of Byte;

Este sería un ejemplo de declaración de interfaz con GUID:

type
IFactura = interface
['{78EAC667-ED60-443B-B84B-5D7AF161B28B}']
procedure Calcular;
end;

¿De donde sacamos ese código? Pues cuando en el editor de Delphi se pulsa la combinación de teclas CTRL + MAYÚSCULAS + G entonces nos genera una GUID aleatoria.

CREANDO PROPIEDADES EN LA INTERFAZ

Pese que la declarión de interfaces es similar a la de las clases hay que tener varias cosas presentes:

- No permiten declarar variables internas.

- No pueden ser instanciadas.

- No se permite especificar la visibilidad de los métodos (private, protected o public).

- Las propiedades no pueden apuntar a variables sino sólo a métodos.

Entonces, ¿como podemos definir propiedades? Hay que definirlas utilizando métodos en vez de variables cuando se definen los parámetros read y write de la propiedad. Sería de este modo:

type
IAlbaran = interface
function Get_Numero: Integer;
function Get_Importe: Real;
procedure Set_Numero( iNumero: Integer );
procedure Set_Importe( rImporte: Real );
procedure Imprimir;

property Numero: Integer read Get_Numero write Set_Numero;
property Importe: Real read Get_Importe write Set_Importe;
end;

y su implementación a través de la clase:

TAlbaran = class( TInterfacedObject, IAlbaran )
private
iNumero: Integer;
rImporte: Real;

public
function Get_Numero: Integer;
function Get_Importe: Real;
procedure Set_Numero( iNumero: Integer );
procedure Set_Importe( rImporte: Real );
procedure Imprimir;

property Numero: Integer read Get_Numero write Set_Numero;
property Importe: Real read Get_Importe write Set_Importe;
end;

implementation

{ TAlbaran }

function TAlbaran.Get_Importe: Real;
begin
Result := rImporte;
end;

function TAlbaran.Get_Numero: Integer;
begin
Result := iNumero;
end;

procedure TAlbaran.Imprimir;
begin
ShowMessage( 'Imprimiendo...' );
end;

procedure TAlbaran.Set_Importe( rImporte: Real );
begin
Self.rImporte := rImporte;
end;

procedure TAlbaran.Set_Numero( iNumero: Integer );
begin
Self.iNumero := iNumero;
end;

Esto nos permite utilizar nuestra interfaz sin llamar a los procedimientos Set y Get de cada campo:

var
Albaran: IAlbaran;
begin
Albaran := TAlbaran.Create;
Albaran.Numero := 1;
Albaran.Importe := 68.21;

ShowMessage( 'Numero=' + IntToStr( Albaran.Numero ) );
ShowMessage( 'Importe=' + FloatToStr( Albaran.Importe ) );
end;

Con esta comodidad se pueden instanciar clases a partir de interfaces manteniendo la claridad de código tanto dentro como fuera de la implementación.

Con esto finalizamos la parte básica de implementación de interfaces en Delphi.

Pruebas realizadas en Delphi 7.

No hay comentarios:

Publicidad