Interfaces

Les interfaces permettent de définir un contrat, au travers d'un ensembles de méthodes et propriétés, sans définir une implémentation. L'implémentation d'une interface sera réalisée au moyen de classe(s) pouvant n'avoir aucun lien de parenté entre elles. Ceci permet un découplage complet entre des interfaces et leur implémentation.

Il s'agit d'un type référence supportant des mécanismes d'abstraction et de virtualisation, les interfaces supportent l'héritage, il s'agit cependant d'un héritage de contrat, et non d'un héritage d'implémentation.

Les interfaces ont nécessairement une ou plusieurs classes comme support d'implémentation, une classe pouvant supporter simultanément plusieurs interfaces différentes non-aparentées.

Déclaration

Toutes les classes dérivent de l'interface racine IInterface, et peuvent être déclarées comme suit:

type
   INomDeLInterface = interface (IInterfaceAncetre)
      ...membres de l'interface...
   end;

Si l'interface ancêtre n'est pas précisée, il s'agira automatiquement de IInterface.

Une interface représentant un contrat, elle n'a ni implémentation ni champs, et uniquement des méthodes, elle peut cependant avoir des propriétés, qui sont alors utilisable comme sucre syntaxique des methoéde.

Par convention, les interfaces sont préfixées d'un "I" suivi d'une majuscule, comme tous les autres types.

Méthodes

Les méthodes peuvent être des function (retourne un résulat), procedure (ne retourne pas un résultat) ou method (retourne optionnellement un résultat).

Elles définissent le contrat de l'interface, un objet souhaitant implémenter une interface devra fournir une implémentation de chacune des méthodes de l'interface.

Propriétés

Les propriétés permettent d'exposer des propriétés d'un objet de manière encapsulée, elles peuvent être simples ou paramétrées:

property ProprieteSimple : TypePropriete [index indexValue] [read Getter] [write Setter];
property ProprieteParametree[parametres...] : TypePropriete [read Getter] [write Setter] [default];

Une proprieté à un Getter et un Setter optionels (au moins une des deux doit être définie). Une propriété ne définissant qu'un Getter sera dite en lecture seule, une propriété ne définissant qu'un Setter sera dit en écriture seule, et une propriété définissant les deux sera dite en lecture écriture.

Pour une propriété simple, le Getter doit être une méthode sans paramètre retournant un résultat du type approprié. Le Setter quand à lui devra être une méthode acceptant un paramètre unique du type de la propriété et ne retournant pas de résultat.

Pour une propriété paramétrée, les Getter/Setter devront être des méthodes, similairement à la propriété simple, mais acceptant les paramètres de la propriété. Une propriété paramétrée pourra être qualifiée avec default, dans ce cas elle sera accessible directement sur une instance de l'objet. Pour les expressions de Setter, la valeur affectée est accessible au travers de l'identificateur Value, elle peuvent correspondre soit à la partie gauche d'une affectation, soit à une instruction.

Opérateurs

  • as permet d'obtenir une interface à partir d'une instance.
  • implements permet de tester de manière dynamique si une classe supporte une interface donnée.

Exemple

type IMyInterface = interface
      procedure Hello;
   end;

type IMyOtherInterface = interface
      procedure World;
   end;

type TTest = class (IMyInterface)
      procedure Hello; begin PrintLn('Hello test'); end;
   end;

type TWorld = class
      procedure Hello; begin PrintLn('Hello world'); end;
   end;
type TSubWorld = class (TWorld, IMyInterface, IMyOtherInterface)
      procedure World; begin PrintLn('subworld'); end;
   end;

var t := new TTest;

PrintLn(t implements IMyInterface);        // True
PrintLn(t implements IMyOtherInterface);   // False

var i := t as IMyInterface;                // Hello test

i.Hello;

var s := new TSubWorld;

PrintLn(s implements IMyInterface);        // True
PrintLn(s implements IMyOtherInterface);   // True

i := s as IMyInterface;

var o := s as IMyOtherInterface;

i.Hello;                                   // Hello world
o.World;                                   // subworld