Lección 6 · 6 de 20
Interfaces · Pascal
Defina interfaces en Object Pascal, impleméntelas en clases sin parentesco y deje que el recuento de referencias libere los objetos solo.

Una interfaz es un contrato: una lista de métodos sin datos ni código. ITax solo dice que hay una función Apply(net). Por convención, su nombre empieza por I.
Las clases TVat (IVA peninsular, 21 %) y TIgic (IGIC canario, 7 %) implementan la interfaz: la nombran tras la clase madre, class(TInterfacedObject, ITax), y escriben su propio Apply. No están emparentadas entre sí; lo único que comparten es el contrato. Una clase hereda de una sola madre, pero puede implementar varias interfaces.
Quote recibe un parámetro de tipo ITax, así que acepta cualquier objeto que cumpla el contrato, venga de la clase que venga. Es la manera de escribir código que no depende de clases concretas.
`TInterfacedObject` aporta el recuento de referencias: cada variable o parámetro de tipo interfaz que apunta al objeto suma uno, y cuando el contador vuelve a cero el objeto se libera solo. Por eso Quote('Madrid', TVat.Create, 250) no necesita Free: el objeto desaparece al terminar la llamada. La variable tax mantiene vivo el suyo hasta tax := nil.
La regla de oro: un objeto que se maneja por interfaz no se libera con Free ni se guarda a la vez en una variable de clase. Si necesita Supports o el operador as con interfaces, añádales un GUID entre corchetes.
Código · main.pas
program main;type ITax = interface function Apply(net: Double): Double; end; TVat = class(TInterfacedObject, ITax) function Apply(net: Double): Double; end; TIgic = class(TInterfacedObject, ITax) function Apply(net: Double): Double; end;function TVat.Apply(net: Double): Double;begin Result := net * 1.21; // mainland Spainend;function TIgic.Apply(net: Double): Double;begin Result := net * 1.07; // Canary Islandsend;procedure Quote(const region: String; tax: ITax; net: Double);begin WriteLn(region:9, ': ', net:7:2, ' net -> ', tax.Apply(net):7:2, ' EUR');end;var tax: ITax;begin Quote('Madrid', TVat.Create, 250); // the object is freed after the call Quote('Tenerife', TIgic.Create, 250); tax := TIgic.Create; // kept alive while tax refers to it Quote('La Palma', tax, 19.99); tax := nil; // last reference gone: freed hereend.Salida · fpc main.pas && ./main
Madrid: 250.00 net -> 302.50 EUR Tenerife: 250.00 net -> 267.50 EUR La Palma: 19.99 net -> 21.39 EUR
Para recordar
- Una interfaz es una lista de métodos que una clase promete cumplir.
- Una clase puede implementar varias interfaces.
- Un parámetro de interfaz acepta cualquier clase que la implemente.
- Con
TInterfacedObject, el objeto se libera solo al quedarse sin referencias. - No mezcle
Freecon objetos manejados por interfaz.
Ejercicio
Cree TExempt = class(TInterfacedObject, ITax) para exportaciones, cuyo Apply devuelva el neto sin impuesto, y añada una línea Quote('Export', TExempt.Create, 250).