IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Contribuez Delphi Discussion :

Assistants de classe/enregistrement (Class/record Helpers), D2009 et supérieur


Sujet :

Contribuez Delphi

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Rédacteur/Modérateur
    Avatar de Andnotor
    Inscrit en
    Septembre 2008
    Messages
    5 933
    Détails du profil
    Informations personnelles :
    Localisation : Autre

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 933
    Par défaut Assistants de classe/enregistrement (Class/record Helpers), D2009 et supérieur
    Bonjour à tous

    A la lecture de certains sujets ces derniers jours, il m'a semblé que les assistants de classe ou d'enregistrement étaient largement méconnus et qu'une discussion traitant spécifiquement de ce sujet, mais surtout avec des exemples concrets, serait intéressante

    Très courte introduction sur les assistants de classe (Class Helpers)
    Les assistants de classe ne sont rien d'autres que l'ajout de mécanismes d'accès aux données d'une classe déterminée. C'est en sorte une amélioration de l'encapsulation (pour parler POO) de cette classe.
    Il n'est pas possible d'ajouter de nouvelles propriétés par l'intermédiaire d'un assistant mais uniquement de la lecture/écriture des propriétés existantes.

    Vous n'avez rien compris ? Attendez !
    Voici un exemple concret que tout le monde à déjà taper des centaines de fois : ExtractFilePath(Application.ExeName);. Ne serait-il pas intéressant de pouvoir simplement invoquer Application.Path ?

    Voici la déclaration et l'implémentation d'un assistant de TApplication :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    type
      TApplicationHelper = class Helper for TApplication
        function Path(aExcludeTrailingDelimiter: boolean = FALSE) :TFileName;
      end;
     
    function TApplicationHelper.Path(aExcludeTrailingDelimiter: boolean): TFileName;
    begin
      Result := ExtractFilePath(ExeName);
     
      if aExcludeTrailingDelimiter then
        Result := ExcludeTrailingPathDelimiter(Result);
    end;
    et dans nos applications :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    //Nous pouvons remplacer ceci...
    MyApp := ExtractFilePath(Application.ExeName) +'MonApp.exe';
    //...par cela
    MyApp := Application.Path +'MonApp.exe';
     
    //et même...
    Path := ExcludeTrailingPathDelimiter(ExtractFilePath(Application.ExeName));
    //...par...
    Path := Application.Path(TRUE);
    C'est plus clair

    Les assistants d'enregistrement
    Alors que pour une classe on pourrait envisager d'autres possibilités comme TUnObjet=class(UneUnité.TUnObjet), les héritages d'enregistrement ne sont pas possibles et dans ce cas, les assistants sont une réelle aide. Ils fonctionnent la même chose que pour les classes.

    Un exemple avec TRect.
    J'ai souvent eu à connaitre les quatre coins d'un rectangle, mais l'implémentation existante ne permet de récupérer sous la forme d'un TPoint que les coins TopLeft et BottomRight.

    Pour ajouter les deux autres:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    type
      TRectHelper = record Helper for TRect
        function TopRight   :TPoint;
        function BottomLeft :TPoint;
      end;
     
    function TRectHelper.BottomLeft: TPoint;
    begin
      Result.X := Left;
      Result.Y := Bottom;
    end;
     
    function TRectHelper.TopRight: TPoint;
    begin
      Result.X := Right;
      Result.Y := Top;
    end;
    Attention, il ne s'agit pas de disserter sur telle ou telle proposition, mais vraiment de générer une bibliothèque de codes utiles, avec exemples.
    Répondre C'est super ! ou à l'inverse Comment je pourrais faire ça ? n'est pas le but ! Mais si un code vous semble intéressant (voire carrément utile), n'hésitez pas à voter

  2. #2
    Rédacteur/Modérateur
    Avatar de Andnotor
    Inscrit en
    Septembre 2008
    Messages
    5 933
    Détails du profil
    Informations personnelles :
    Localisation : Autre

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 933
    Par défaut Ajouter le test "vide" sur un TEdit
    Pour tester si un TEdit contient ou non du texte:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    type
      TEditHelper = class Helper for TEdit
      private
        function  GetEmpty: boolean;
      public
        property  Empty :boolean read GetEmpty;
      end;
     
    function TEditHelper.GetEmpty: boolean;
    begin
      Result := Text = '';
    end;
    Nous remplacerons ainsi :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    if (Edit3.Text <> '') And (Edit4.Text = '') And (Edit5.Text = '') And...
    par:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    if not Edit3.Empty And Edit4.Empty And Edit5.Empty And...

  3. #3
    Rédacteur/Modérateur
    Avatar de Andnotor
    Inscrit en
    Septembre 2008
    Messages
    5 933
    Détails du profil
    Informations personnelles :
    Localisation : Autre

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 933
    Par défaut Path, Name, Ext depuis un TFileName
    Plus intéressant, la manipulation des chaînes qui se gère comme un enregistrement. Ici, l'extraction des données d'un TFileName (type string):

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
      TFileNameHelper = record Helper for TFileName
      private
        function  GetEmpty: boolean;
        function  GetExt: string;
        function  GetName: string;
        function  GetPath: string;
        procedure SetExt(const Value: string);
      public
        property  Empty :boolean read GetEmpty;
        property  Path :string read GetPath;
        property  Name :string read GetName;
        property  Ext :string read GetExt write SetExt;
      end;
     
    function TFileNameHelper.GetExt: string;
    begin
      Result := ExtractFileExt(Self);
    end;
     
    function TFileNameHelper.GetEmpty: boolean;
    begin
      Result := self = '';
    end;
     
    function TFileNameHelper.GetName: string;
    begin
      Result := ExtractFileName(Self);
    end;
     
    function TFileNameHelper.GetPath: string;
    begin
      Result := ExtractFilePath(Self);
    end;
     
    procedure TFileNameHelper.SetExt(const Value: string);
    begin
      Self := ChangeFileExt(Self, Value);
    end;
    On remarque ici que Self représente la chaîne.

  4. #4
    Rédacteur/Modérateur
    Avatar de Andnotor
    Inscrit en
    Septembre 2008
    Messages
    5 933
    Détails du profil
    Informations personnelles :
    Localisation : Autre

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 933
    Par défaut Lecture/écriture multichaînes dans la base des registres (MULTI_SZ)
    La lecture/écriture de valeurs multichaînes dans la base des registres n'a jamais été implémentée dans TRegistry ! Voici de quoi palier à cette absence.
    Les chaînes sont séparées par #0 et la donnée se termine par #0#0.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    type
      TRegistryHelper = class Helper for TRegistry
      public
        function  ReadMultiString(const aName: string): string;
        procedure WriteMultiString(const aName: string; aValue: string);
      end;
     
    function TRegistryHelper.ReadMultiString(const aName: string): string;
    var
      i: integer;
    begin
      SetLength(Result, GetDataSize(aName) div SizeOf(Char));
      ReadBinaryData(aName, Result[1], GetDataSize(aName));
     
      for i := 1 to Length(Result) do
        if Result[i] = #0 then
          Result[i] := #13;
    end;
     
    procedure TRegistryHelper.WriteMultiString(const aName: string; aValue: string);
    begin
      aValue := StringReplace(aValue, #13, #0, [rfReplaceAll]) +#0;
      RegSetValueEx(CurrentKey, PChar(aName), 0, REG_MULTI_SZ, PChar(aValue), Length(aValue) *SizeOf(Char));
    end;
    La lecture par ReadBinaryData ne pose pas de problème, mais il faut obligatoirement passer par l'API RegSetValueEx pour que la donnée soit définie en MULTI_SZ.

  5. #5
    Membre Expert
    Avatar de e-ric
    Homme Profil pro
    Apprenti chat, bienfaiteur de tritons et autres bestioles
    Inscrit en
    Mars 2002
    Messages
    1 568
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 56
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Apprenti chat, bienfaiteur de tritons et autres bestioles

    Informations forums :
    Inscription : Mars 2002
    Messages : 1 568
    Par défaut
    Salut

    Dans l'idée, C'est proche du Design Pattern Décorateur, non ?
    C'est valable depuis quelle version de Delphi ?

    L'article soulève un sujet assez rarement discuté, c'est une bonne idée.

    @+

    M E N S . A G I T A T . M O L E M
    Debian 64bit, Lazarus + FPC -> n'oubliez pas de consulter les FAQ Delphi et Pascal ainsi que les cours et tutoriels Delphi et Pascal

    "La théorie, c'est quand on sait tout, mais que rien ne marche. La pratique, c'est quand tout marche, mais qu'on ne sait pas pourquoi. En informatique, la théorie et la pratique sont réunies: rien ne marche et on ne sait pas pourquoi!".
    Mais Emmanuel Kant disait aussi : "La théorie sans la pratique est inutile, la pratique sans la théorie est aveugle."

  6. #6
    Expert éminent
    Avatar de Paul TOTH
    Homme Profil pro
    Freelance
    Inscrit en
    Novembre 2002
    Messages
    8 964
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 56
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Freelance
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2002
    Messages : 8 964
    Par défaut
    les class helper ont été introduit dans Delphi for .Net afin d'ajouter des méthodes à des objets .Net

    je trouve la syntaxe pas très élégante, à mon avis elle est à éviter pour éviter les confusions. Exemple:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    type
      TMonObject = class
        function Value: Integer;
      end;
     
    var
      o: TMonObject;
    begin
      o := TMonObject.Create;
      o.Eval('10');
    end;
    quand on regarde ce code on est tout de même assez surpris que ça compile...il faut trouver le class helper qui déclare la méthode Eval pour comprendre ce qu'il se passe.

    C'est théoriquement à utiliser uniquement sur des classes objets qu'on ne peut pas dériver - par exemple les propriétés objets d'un composant Memo.Lines - mais s'il est possible de dériver l'objet il est préférable à mon sens de le faire.
    Developpez.com: Mes articles, forum FlashPascal
    Entreprise: Execute SARL
    Le Store Excute Store

Discussions similaires

  1. classe enregistrement audio
    Par cyriltec dans le forum C#
    Réponses: 2
    Dernier message: 30/03/2010, 09h52
  2. Réponses: 5
    Dernier message: 08/12/2004, 20h42
  3. Visibilité de methodes dans Classe de Class
    Par Math75 dans le forum C++
    Réponses: 9
    Dernier message: 28/09/2004, 12h48
  4. Réponses: 7
    Dernier message: 10/09/2004, 14h28
  5. pb constructeurs classes dérivant classe abstraite
    Par Cornell dans le forum Langage
    Réponses: 2
    Dernier message: 10/02/2003, 19h02

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo