Recherche…


Remarques

Les interfaces sont utilisées pour décrire les informations nécessaires et la sortie attendue des méthodes et des classes, sans fournir d'informations sur l'implémentation explicite.

Les classes peuvent implémenter des interfaces et les interfaces peuvent hériter les unes des autres. Si une classe implémente une interface, cela signifie que toutes les fonctions et procédures exposées par l'interface existent dans la classe.

Un aspect particulier des interfaces dans delphi est que les instances d'interfaces ont une gestion de la durée de vie basée sur le comptage des références. La durée de vie des instances de classe doit être gérée manuellement.

Compte tenu de tous ces aspects, des interfaces peuvent être utilisées pour atteindre différents objectifs:

  • Fournir plusieurs implémentations différentes pour les opérations (par exemple enregistrer dans un fichier, une base de données ou envoyer un courrier électronique, le tout en tant qu'interface "SaveData")
  • Réduire les dépendances, améliorer le découplage et ainsi rendre le code plus facile à maintenir et à tester
  • Travaillez avec des instances dans plusieurs unités sans être gêné par la gestion de la durée de vie (même si des pièges existent, faites attention!)

Définition et implémentation d'une interface

Une interface est déclarée comme une classe, mais sans modificateurs d'accès ( public , private , ...). De plus, aucune définition n'est autorisée, donc les variables et les constantes ne peuvent pas être utilisées.

Les interfaces doivent toujours avoir un identifiant unique , qui peut être généré en appuyant sur Ctrl + Maj + G.

IRepository = interface
    ['{AFCFCE96-2EC2-4AE4-8E23-D4C4FF6BBD01}']
    function  SaveKeyValuePair(aKey: Integer; aValue: string): Boolean;
end;

Pour implémenter une interface, le nom de l'interface doit être ajouté derrière la classe de base. En outre, la classe doit être un descendant de TInterfacedObject (cela est important pour la gestion de la durée de vie ).

TDatabaseRepository = class(TInterfacedObject, IRepository)
    function  SaveKeyValuePair(aKey: Integer; aValue: string): Boolean;
end;

Lorsqu'une classe implémente une interface, elle doit inclure toutes les méthodes et fonctions déclarées dans l'interface, sinon elle ne sera pas compilée.

Une chose à noter est que les modificateurs d'accès n'ont aucune influence si l'appelant travaille avec l'interface. Par exemple, toutes les fonctions de l'interface peuvent être implémentées en tant que membres strict private , mais peuvent toujours être appelées à partir d'une autre classe si une instance de l'interface est utilisée.

Implémentation de plusieurs interfaces

Les classes peuvent implémenter plusieurs interfaces, par opposition à l'héritage de plusieurs classes ( Multiple Inheritance ), ce qui n'est pas possible pour les classes Delphi. Pour ce faire, le nom de toutes les interfaces doit être ajouté à la classe de base.

Bien entendu, la classe d'implémentation doit également définir les fonctions déclarées par chacune des interfaces.

IInterface1 = interface
    ['{A2437023-7606-4551-8D5A-1709212254AF}']
    procedure Method1();
    function Method2(): Boolean;
end;

IInterface2 = interface
    ['{6C47FF48-3943-4B53-8D5D-537F4A0DEC0D}']
    procedure SetValue(const aValue: TObject);
    function  GetValue(): TObject;

    property Value: TObject read GetValue write SetValue;
end;

TImplementer = class(TInterfacedObject, IInterface1, IInterface2)
    // IInterface1
    procedure Method1();
    function Method2(): Boolean;

    // IInterface2
    procedure SetValue(const aValue: TObject);
    function  GetValue(): TObject

    property Value: TObject read GetValue write SetValue;
end;

Héritage des interfaces

Les interfaces peuvent hériter les unes des autres, exactement comme les classes aussi. Une classe d'implémentation doit donc implémenter des fonctions de l'interface et de toutes les interfaces de base. De cette façon, cependant, le compilateur ne sait pas que la classe implicite implémente également l'interface de base, elle ne connaît que les interfaces explicitement répertoriées. C'est pourquoi l'utilisation as ISuperInterface sur TImplementer ne fonctionnerait pas. Cela se traduit également par la pratique courante d'implémenter explicitement toutes les interfaces de base (dans ce cas, TImplementer = class(TInterfacedObject, IDescendantInterface, ISuperInterface) ).

ISuperInterface = interface
    ['{A2437023-7606-4551-8D5A-1709212254AF}']
    procedure Method1();
    function Method2(): Boolean;
end;

IDescendantInterface = interface(ISuperInterface)
    ['{6C47FF48-3943-4B53-8D5D-537F4A0DEC0D}']
    procedure SetValue(const aValue: TObject);
    function  GetValue(): TObject;

    property Value: TObject read GetValue write SetValue;
end;

TImplementer = class(TInterfacedObject, IDescendantInterface)
    // ISuperInterface
    procedure Method1();
    function Method2(): Boolean;

    // IDescendantInterface
    procedure SetValue(const aValue: TObject);
    function  GetValue(): TObject

    property Value: TObject read GetValue write SetValue;
end;

Propriétés dans les interfaces

La déclaration de variables dans les interfaces n'étant pas possible, la manière "rapide" de définir les property Value: TObject read FValue write FValue; ( property Value: TObject read FValue write FValue; ) ne peut pas être utilisée. Au lieu de cela, le Getter et le setter (chacun seulement si nécessaire) doivent également être déclarés dans l'interface.

IInterface = interface(IInterface)
    ['{6C47FF48-3943-4B53-8D5D-537F4A0DEC0D}']
    procedure SetValue(const aValue: TObject);
    function  GetValue(): TObject;

    property Value: TObject read GetValue write SetValue;
end;

Une chose à noter est que la classe d'implémentation n'a pas à déclarer la propriété. Le compilateur accepterait ce code:

TImplementer = class(TInterfacedObject, IInterface)
    procedure SetValue(const aValue: TObject);
    function  GetValue(): TObject
end;

Une mise en garde, cependant, est que de cette manière, la propriété ne peut être accédée que via une instance de l'interface, non pas à travers la classe elle-même. De plus, l'ajout de la propriété à la classe augmente la lisibilité.



Modified text is an extract of the original Stack Overflow Documentation
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow