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

Langage Delphi Discussion :

Les limites de l'implements ?


Sujet :

Langage Delphi

  1. #21
    Membre éclairé Avatar de Kaféine
    Homme Profil pro
    Inscrit en
    Avril 2007
    Messages
    569
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Avril 2007
    Messages : 569
    Points : 736
    Points
    736
    Par défaut
    Je vous propose un petit exemple de monnayeur en rapport avec un post que j'ai vu sur un distributeur.
    Pour cela j'utilise les interfaces et j'ai essayé de mettre tous les concepts vus dans cette discution.
    Notamment, dérivation d'interface, délégation.

    pour la délégation, j'utilise une réference d'interface pour l'attribut privé (ISimpleCalculatrice).

    Je connaissais pas TAggregatedObject mais d'aprés ce que j'ai compris, si Mon TMonnayeur avait dérivé de cette objet,
    aurait fallu utiliser une référence objet pour l'attribut privé.

    Bref, j'attend vos commentaires la dessus, enfin s'il y en a

    unité avec les différentes interfaces et classes:

    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
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
     
    unit UIntf;
     
    interface
     
    type
      IPrix = interface
        ['{25E1408C-4464-407E-B723-765BAB9A3733}']
        function GetPrix: Currency;
        procedure SetPrix(const Prix: Currency);
        property Prix: Currency read GetPrix write SetPrix;
      end;
     
      TPrix = class(TInterfacedObject, IPrix)
      private
        FPrix: Currency;
      protected
        function GetPrix: Currency;
        procedure SetPrix(const Prix: Currency);
      public
        property Prix: Currency read GetPrix;
      end;
     
      IArticle = interface(IPrix)
        ['{312BFCEE-DBF6-4669-826C-D340107D15CF}']
        function GetNom: string;
        procedure SetNom(const UnNom: string);
        property Nom: string read GetNom write SetNom; 
      end;
     
      TArticle = class(TPrix, IPrix, IArticle)
      private
        FNom: string;
      protected
        function GetNom: string;
        procedure SetNom(const UnNom: string);
      public
        property Nom: string read FNom write FNom;
      end;
     
      ISimpleCalculatrice = interface
        ['{9DA2B6EC-E79E-41CE-B72C-3969F89A888A}']
        function Ajouter(const V: Currency): Currency;
        function Soustraire(const a: Currency): Currency;
        function GetValeur: Currency;
        procedure SetValeur(const Value: Currency);
        property Valeur: Currency read GetValeur write SetValeur;
      end;
     
      TSimpleCalculatrice = class(TInterfacedObject, ISimpleCalculatrice)
      private
        FValeur: Currency;
      protected
        function GetValeur: Currency;
        procedure SetValeur(const Value: Currency);
      public
        constructor Create;
        function Ajouter(const Val: Currency): Currency;
        function Soustraire(const Val: Currency): Currency;
        property Valeur: Currency read GetValeur write SetValeur;
      end;
     
      IMonnayeur = interface
        ['{AAEB84F2-64A6-45F8-8310-246D8878BDD5}']
        function GetArgentDonnee: Currency;
        procedure SetArgentDonnee(const Tune: Currency);
        property ArgentDonnee: Currency read GetArgentDonnee write SetArgentDonnee;
        function GetArticle: IArticle;
        procedure SetArticle(const Article: iArticle);
        property Article: IArticle read GetArticle write SetArticle;
        function MonnaieRendue: Currency;
      end;
     
      TMonnayeur = class(TInterfacedObject, ISimpleCalculatrice, IMonnayeur)
      private
        FSimpleCalculatrice: ISimpleCalculatrice;
        FArticle: IArticle;
        FArgentDonnee: Currency;
      protected
        function GetArgentDonnee: Currency;
        procedure SetArgentDonnee(const Tune: Currency);
        function GetArticle: IArticle;
        procedure SetArticle(const Article: IArticle);
      public
        constructor Create;
        function MonnaieRendue: Currency;
        property Article: IArticle read GetArticle write SetArticle;
        property ArgentDonnee: Currency read GetArgentDonnee write SetArgentDonnee;
        property SimpleCalculatrice: ISimpleCalculatrice read FSimpleCalculatrice implements ISimpleCalculatrice;
      end;
     
     
     
    implementation
     
     
    { TPrix }
     
    function TPrix.GetPrix: Currency;
    begin
      Result := FPrix;
    end;
     
    procedure TPrix.SetPrix(const Prix: Currency);
    begin
      FPrix := Prix;
    end;
     
    { TSimpleCalculatrice }
     
    function TSimpleCalculatrice.Ajouter(const Val: Currency): Currency;
    begin
      FValeur := FValeur + Val;
      Result := FValeur;
    end;
     
    constructor TSimpleCalculatrice.Create;
    begin
      inherited Create;
      FValeur := 0;
    end;
     
    function TSimpleCalculatrice.GetValeur: Currency;
    begin
      Result := FValeur;
    end;
     
    procedure TSimpleCalculatrice.SetValeur(const Value: Currency);
    begin
      FValeur := Value;
    end;
     
    function TSimpleCalculatrice.Soustraire(const Val: Currency): Currency;
    begin
      FValeur := FValeur - Val;
      Result := FValeur;
    end;
     
    { TMonnayeur }
     
    constructor TMonnayeur.Create;
    begin
      inherited Create;
      FSimpleCalculatrice := TSimpleCalculatrice.Create;
    end;
     
    function TMonnayeur.GetArgentDonnee: Currency;
    begin
      Result := FArgentDonnee;
    end;
     
    function TMonnayeur.GetArticle: IArticle;
    begin
      Result := FArticle;
    end;
     
    function TMonnayeur.MonnaieRendue: Currency;
    begin
      with SimpleCalculatrice do
      begin
        Valeur := 0;
        Ajouter(FArgentDonnee);
        Soustraire(FArticle.Prix);
        Result := Valeur;
      end;
    end;
     
    procedure TMonnayeur.SetArgentDonnee(const Tune: Currency);
    begin
      FArgentDonnee := Tune;
    end;
     
    procedure TMonnayeur.SetArticle(const Article: IArticle);
    begin
      FArticle := Article;
    end;
     
    { TArticle }
     
    function TArticle.GetNom: string;
    begin
      Result := FNom;
    end;
     
    procedure TArticle.SetNom(const UnNom: string);
    begin
      FNom := UnNom;
    end;
     
    end.

    le mini-projet complet en piece jointe.
    Fichiers attachés Fichiers attachés
    Akim Merabet

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

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

    Informations forums :
    Inscription : Novembre 2002
    Messages : 8 964
    Points : 28 445
    Points
    28 445
    Par défaut
    ok, voici mes commentaires

    - OnCreate sert à ne pas surcharger le constructor

    - pourquoi manipuler les classes comme des Interfaces alors que leur usage en tant que classe produit le même effet ?

    - faut vraiment être fan des objets pour créer une interface et une classe juste pour faire des additions et des soustractions

    - au final, à quoi cela sert-il de déclarer dans interfaces dans cet exemple ?

    Voila, je veux bien imaginer que cet exemple propose de montrer l'usage des interfaces en supposant que dans un contexte plus complexe cela présente un intérêt, mais déjà là je vois des choses qui clochent :

    - dans tes interfaces, à quoi servent les GUID ?

    - pourquoi déclarer une interface IPrix alors que ton monnayeur manipule de Currency...s'il manipulait des IPrix j'aurais pu comprendre.

    Developpez.com: Mes articles, forum FlashPascal
    Entreprise: Execute SARL
    Le Store Excute Store

  3. #23
    Membre éclairé Avatar de Kaféine
    Homme Profil pro
    Inscrit en
    Avril 2007
    Messages
    569
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Avril 2007
    Messages : 569
    Points : 736
    Points
    736
    Par défaut
    OnCreate sert à ne pas surcharger le constructor
    oui mais j'avais envie de le surcharger....

    pourquoi manipuler les classes comme des Interfaces alors que leur usage en tant que classe produit le même effet
    une intérêts des interfaces c'est le compteur de référence. je profite donc du système pour liberer automatiquement.
    (les objet dans la form principal sont libéré automatiquement)

    faut vraiment être fan des objets pour créer une interface et une classe juste pour faire des additions et des soustractions
    oui tu m'as démasqué, je suis fan des objets. ici l'exemple est simple, imagine quelque chose de plus complexe avec plus d'opération par exemple...

    au final, à quoi cela sert-il de déclarer dans interfaces dans cet exemple
    Le monnayeur n'est pas un homme-grenouille mais a la fois un monnayeur et une simple calculatrice


    dans tes interfaces, à quoi servent les GUID
    pour l'interrogation d'interface.. QueryInterface et opérateur as.

    pourquoi déclarer une interface IPrix alors que ton monnayeur manipule de Currency...s'il manipulait des IPrix j'aurais pu comprendre
    Article descend de prix et le monnayeur manipule des articles.

    ce bout de code a été codé vite sans prendre le temps d'une parfaite d'analyse
    Akim Merabet

  4. #24
    Membre du Club
    Profil pro
    Inscrit en
    Avril 2008
    Messages
    42
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2008
    Messages : 42
    Points : 51
    Points
    51
    Par défaut
    Bonjour,

    cette discussion est intéressante (au point que j'ai créé un compte pour y participer )

    Moi même je suis utilisateur assidu des interfaces sous Delphi, au point, comme dans l'exemple de Kaféine, d'accompagner quasiment toute création de classe par son (ses) interface(s), et de n'utiliser dans les projets que des références d'interfaces.

    Citation Envoyé par Kaféine Voir le message
    Bref, j'attend vos commentaires la dessus, enfin s'il y en a
    J'ai testé le projet et, comme l'indique Suryavarman, il semble y avoir un problème de memory leak dans l'implémentation de implements

    en effet, j'ai rajouté ce bout de code dans le projet de Kaféine :

    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
     
    procedure TfrmTestInterface.CalculBtnClick(Sender: TObject);
    // on va juste utiliser la fonctionnalité "calculatrice" du monnayeur
    // pour faire une addition :
    // (ajouter 3 TEdit sur la fiche, de manière à ce que le calcul soit  : Edit1 + Edit2 = Edit3)
    var calc:ISimpleCalculatrice;
        a,b:Currency;
    begin
      calc := TMonnayeur.create as ISimpleCalculatrice;
      a := StrToCurrDef(Edit1.Text, 0);
      b := StrToCurrDef(Edit2.Text, 0);
      calc.Ajouter(a);
      calc.Ajouter(b);
      Edit3.text := Format('%f', [calc.Valeur]);
    end;
    lorsque je lance le calcul, ReportMemoryLeaksOnShutdown signale
    un problème à la sortie du programme. Ce qui, puisque on utilise une référence d'interface, ne devrait pas être le cas...

    il semblerait bien que, comme indiqué dans l'aide de BDS2007, utiliser TAggregatedObject soit indispensable dans l'utilisation d'implements, et c'est dommage... car alors la classe utilisée pour implements ne peut servir qu'a faire des implements et ne peut pas être réutilisée dans un autre contexte plus simple (voir commentaires sur TAggregatedObject dans system.pas)

    Quelqu'un a-t-il une solution a ce pb de leak sans utiliser TAggregatedObject ?

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

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

    Informations forums :
    Inscription : Novembre 2002
    Messages : 8 964
    Points : 28 445
    Points
    28 445
    Par défaut
    voici un code qui met en valeur le comportement de implements
    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
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
     
    type
     IChildObject=interface
      procedure SayHello;
     end;
     
     TInterfacedObject=class(TObject)
     private
      fCount:integer;
      function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
      function _AddRef: Integer; stdcall;
      function _Release: Integer; stdcall;
     end;
     
     TAggregatedObject=class(TObject)
     private
      fController:IInterface;
      function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
      function _AddRef: Integer; stdcall;
      function _Release: Integer; stdcall;
     public
      constructor Create(AController:IInterface);
     end;
     
     TChildObject1=class(TInterfacedObject,IChildObject)
     public
      procedure SayHello;
     end;
     
     TParentObject1=class(TInterfacedObject,IChildObject)
     private
      fChild:IChildObject;
     public
      constructor Create;
      property Child:IChildObject read fChild implements IChildObject;
     end;
     
     TChildObject2=class(TAggregatedObject,IChildObject)
     public
      procedure SayHello;
     end;
     
     TParentObject2=class(TInterfacedObject,IInterface,IChildObject)
     private
      fChild:IChildObject;
     public
      constructor Create;
      property Child:IChildObject read fChild implements IChildObject;
     end;
     
    function TInterfacedObject.QueryInterface(const IID: TGUID; out Obj): HResult;
    begin
     WriteLn(ClassName,'.QueryInterface');
     if GetInterface(IID, Obj) then
       Result := 0
     else
       Result := E_NOINTERFACE;
    end;
     
    function TInterfacedObject._AddRef: Integer;
    begin
     inc(fCount);
     Result:=fCount;
     WriteLn(ClassName,'._AddRef=',Result);
    end;
     
    function TInterfacedObject._Release: Integer;
    begin
     dec(fCount);
     Result:=fCount;
     WriteLn(ClassName,'._Release=',Result);
     if fCount=0 then Free;
    end;
     
    constructor TAggregatedObject.Create(AController:IInterface);
    begin
     fController:=AController;
    end;
     
    function TAggregatedObject.QueryInterface(const IID: TGUID; out Obj): HResult;
    begin
     Write(ClassName,'.QueryInterface->');
     Result:=fController.QueryInterface(IID,Obj);
    end;
     
    function TAggregatedObject._AddRef: Integer;
    begin
     WriteLn(ClassName,'._AddRef->');
    // Result:=fController._AddRef;
    end;
     
    function TAggregatedObject._Release: Integer;
    begin
     Write(ClassName,'._Release->');
     Result:=fController._Release;
    end;
     
    procedure TChildObject1.SayHello;
    begin
     ShowMessage('Hello');
    end;
     
    constructor TParentObject1.Create;
    begin
     fChild:=TChildObject1.Create;
    end;
     
    procedure TChildObject2.SayHello;
    begin
     ShowMessage('Hello');
    end;
     
    constructor TParentObject2.Create;
    begin
     fChild:=TChildObject2.Create(Self);
    end;
     
    procedure TForm1.FormCreate(Sender: TObject);
    var
     i:IChildObject;
    begin
     AllocConsole;
     Writeln('Mode 1');
     i:=TParentObject1.Create;
     i.SayHello;
     i:=nil;
     Writeln('Mode 2');
     i:=TParentObject2.Create;
     i.SayHello;
     i:=nil;
    end;
    en créant une classe avec un implements, on a 2 AddRef pour 1 Release

    dans le "mode 2" l'aggregated object n'appelle pas AddRef chez son parent pour tomber sur le bon compte (ce n'est pas ce que fait l'objet Delphi)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    Mode 1
    TChildObject1._AddRef=1
    TChildObject1._AddRef=2
    TChildObject1._Release=1
    Mode 2
    TParentObject2._AddRef=1
    TParentObject2._AddRef=2
    TParentObject2._Release=1
    TChildObject2._AddRef->
    TChildObject2._AddRef->
    TChildObject2._Release->TParentObject2._Release=0
    TChildObject2._Release->TParentObject2._Release=-1
    notez que le dernier Release négatif est du au Free
    Developpez.com: Mes articles, forum FlashPascal
    Entreprise: Execute SARL
    Le Store Excute Store

  6. #26
    Expert confirmé

    Profil pro
    Leader Technique
    Inscrit en
    Juin 2005
    Messages
    1 756
    Détails du profil
    Informations personnelles :
    Âge : 46
    Localisation : France, Rhône (Rhône Alpes)

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

    Informations forums :
    Inscription : Juin 2005
    Messages : 1 756
    Points : 4 170
    Points
    4 170
    Par défaut
    Article descend de prix et le monnayeur manipule des articles.

    ce bout de code a été codé vite sans prendre le temps d'une parfaite d'analyse
    Moi il y a une autre chose qui me choque. Pourquoi Article descend de prix ?

    Ca m'a tout l'air d'être un bel exemple d'héritage d'implémentation qu'il vaudrait mieux éviter dans un modèle objet. Il n'y a pas de sémantique dans cet héritage, c'est juste pour se faciliter le codage. Tôt ou tard ça posera problème :
    Un article possède un prix, mais un article n'est pas un prix. Comment tu fais si par la suite, ton article doit avoir deux prix (un prix d'achat et un prix de vente par exemple) ?.

    Pour moi, on est dans un cas typique où le prix aurait dû être géré par agrégation/déléguation et non pas par héritage.

    L'intérêt d'un modèle objet, c'est de pouvoir s'adapter facilement aux évolutions des besoins. Mais si le modèle est bancale au départ...

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

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

    Informations forums :
    Inscription : Novembre 2002
    Messages : 8 964
    Points : 28 445
    Points
    28 445
    Par défaut
    ah ben oui, très juste

    et entre nous, si pour une exemple avec 3 interfaces y'a déjà des erreurs de conception, ça craint pour une projet plus conséquent

    c'est une des raisons pour lesquelles je ne programme pas en 100% objet. Je n'utilise les objets que lorsqu'ils me facilitent le travail ...ce qui est souvent le cas, mais ce n'est pas systématique.
    Developpez.com: Mes articles, forum FlashPascal
    Entreprise: Execute SARL
    Le Store Excute Store

  8. #28
    Membre éclairé Avatar de Kaféine
    Homme Profil pro
    Inscrit en
    Avril 2007
    Messages
    569
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Avril 2007
    Messages : 569
    Points : 736
    Points
    736
    Par défaut
    Citation Envoyé par Franck SORIANO
    Moi il y a une autre chose qui me choque. Pourquoi Article descend de prix ?
    ca me rappelle un film ou le prof de math donne un probleme aux élèves. Un des élèves demande aux profs s'il
    peut remplacer les Paris Match par des Voici, et le prof lui repond, "oui si ca peut t'aider"...
    Enfin tout ca pour vous redire que le but de la mainoeuvre c'était de mettre tous les concepts.

    Citation Envoyé par Franck SORIANO
    L'intérêt d'un modèle objet, c'est de pouvoir s'adapter facilement aux évolutions des besoins. Mais si le modèle est bancale au départ...
    tout à fait sauf que la plupart du temps un modéle se travaille, est réfléchi. ca n'a pas été le cas ici...


    Citation Envoyé par Paul TOTH
    et entre nous, si pour une exemple avec 3 interfaces y'a déjà des erreurs de conception, ça craint pour une projet plus conséquent
    lol, c'est pas parce que j'ai fait des erreurs qu'il faut le généraliser. La plupart du temps un projet plus conséquent ne se fait pas en 15 min.


    Enfin le truc j'ai que j'aurai du mettre des ITruc et des IFoo à la place dans cette exercice, (je renvois au magasine). y'aurais eu
    moins de soucis....
    Akim Merabet

  9. #29
    Membre éclairé Avatar de Kaféine
    Homme Profil pro
    Inscrit en
    Avril 2007
    Messages
    569
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Avril 2007
    Messages : 569
    Points : 736
    Points
    736
    Par défaut
    Citation Envoyé par DenDemble
    lorsque je lance le calcul, ReportMemoryLeaksOnShutdown signale
    un problème à la sortie du programme. Ce qui, puisque on utilise une référence d'interface, ne devrait pas être le cas...
    Effectivement, il y a un probleme de leak dans ce cas précis.

    Je reprend et modifie un peu ton bout de code pour éviter le leak.
    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
     
    procedure TfrmTestInterface.CalculBtnClick(Sender: TObject);
    var 
     Mo : TMonnayeur;
     Calc: ISimpleCalculatrice;
    begin
     
      //je crée un monnayeur
      MO := TMonnayeur.Create;
     
      //et j'utilise son service calculatrice pour faire un calcul
       if Mo.GetInterface(ISimpleCalculatrice, Calc) then
       begin
         Calc.Valeur := 10;
         Calc.Ajouter(50);
         Calc.Ajouter(40);
         ShowMessage(CurrToStr(Calc.Valeur));
       end;
     
       //enfin je libere le monnayeur
       Mo.free; 
    end;
    ceci ne pose pas de problème.
    l'utilisation du FMonnayeur de la form principal non plus

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    procedure TfrmTestInterface.Button1Click(Sender: TObject);
    begin
      (FMonnayeur as ISimpleCalculatrice).Valeur := 10;
      (FMonnayeur as ISimpleCalculatrice).Ajouter(10);
      Showmessage(CurrToStr((FMonnayeur as ISimpleCalculatrice).Valeur));
    end;
    Akim Merabet

  10. #30
    Membre du Club
    Profil pro
    Inscrit en
    Avril 2008
    Messages
    42
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2008
    Messages : 42
    Points : 51
    Points
    51
    Par défaut
    Citation Envoyé par Kaféine Voir le message
    Effectivement, il y a un probleme de leak dans ce cas précis.
    Je reprend et modifie un peu ton bout de code pour éviter le leak.
    En fait il n'y a pas qu'un problème de leak dans le projet,
    la manière dont l'implements est réalisé dans ton projet est erronée.

    La seule manière avec laquelle j'arrive à le faire fonctionner correctement est en utilisant TAggregatedObject comme ancètre de TSimpleCalculatrice. Et là, je suis obligé, comme tu l'as fait remarquer, d'utiliser une référence objet pour l'attribut privé.

    Explications :

    Dans ton exemple, si j'utilise TMonnayeur en l'associant lors de sa première création à la référence d'interface ISimpleCalculatrice, alors tout foire :

    1/dans mon "bout de code", on tombe sur un problème de memoryleak alors qu'on utilise une référence d'interface avec une classe dérivant de TInterfacedObject. Ce qui ne devrait pas être le cas, donc l'implémentation de l'objet comprend un bug, puisque le ref counting a étré cassé par l'implementation.

    2/ Essayons de remplacer dans la fiche de l'exemple la référence d'interface utilisée par FMonnayeur par une autre (ce qui est possible, puisque TMonnayeur implemente les interfaces IUnknow, IInterface, ISimpleCalculatrice, IMonnayeur)

    par exemple (mais ca n'est que pour faire un exemple) : utilisons IInterface
    (attention ici je crois que ca ne fc pas avec delphi 5 par exemple, mais ok avec delphi 2007)
    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
     
     
      TfrmTestInterface = class(TForm)
        edtArgentDonnee: TEdit;
        Label1: TLabel;
        lblMonnaie: TLabel;
        rgArticles: TRadioGroup;
        lblPrixArt: TLabel;
        btnLacheLesPiece: TButton;
        procedure rgArticlesClick(Sender: TObject);
        procedure btnLacheLesPieceClick(Sender: TObject);
      private
        FArticleCourant: IArticle;
        FArt1, FArt2: IArticle;
        FMonnayeur: IInterface;   // j'ai juste remplacé ici IMonnayeur par IInterface
                                  // ca marche car FMonnayeur est utilisé plus bas avec un "as" :
                                  // with FMonnayeur as IMonnayeur do
                                  // ...
        procedure SetArticleCourant(const Value: IArticle);
      public
        constructor Create(AOwner: TComponent); override;
        property ArticleCourant: IArticle read FArticleCourant write SetArticleCourant;
      end;
    Avec ce changement, tous semble continuer a fonctionner normalement,
    l'implements fonctionne, comme dans ton projet exemple initial, et il n'y a pas de memoryleak, comme dans ton projet initial...

    Maintenant, au lieu d'utiliser IInterface, essaye avec ISimpleCalculatrice...
    alors ?

    Ca devrait fonctionner, or ce n'est plus le cas,
    Alors certes ton projet exemple fonctionne, mais il utilise une implementation de la classe TMonnayeur qui n'est pas Robuste et qui ne marche que si on l'utilise d'une certaine manière, ce qui a mon avis il faut a tout prix éviter...

    Utilise TAggregatedObject et alors tout marchera normalement...

  11. #31
    Membre du Club
    Profil pro
    Inscrit en
    Avril 2008
    Messages
    42
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2008
    Messages : 42
    Points : 51
    Points
    51
    Par défaut
    Citation Envoyé par Paul TOTH Voir le message
    voici un code qui met en valeur le comportement de implements
    Je n'ai pas encore analysé l'exemple, mais j'ai déjà une première remarque :

    On n'a pas la même version de Delphi ?

    Moi j'ai Delphi 2007, et dans system.pas TAggregatedObject n'est pas implémenté de la même manière que dans l'exemple :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
      TAggregatedObject = class(TObject)
      private
        FController: Pointer;  // weak reference to controller
        function GetController: IInterface;
      protected
        { IInterface }
        function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
        function _AddRef: Integer; stdcall;
        function _Release: Integer; stdcall;
      public
        constructor Create(const Controller: IInterface);
        property Controller: IInterface read GetController;
      end;
    et plus bas...

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    constructor TAggregatedObject.Create(const Controller: IInterface);
    begin
      // weak reference to controller - don't keep it alive
      FController := Pointer(Controller);
    end;
     
    function TAggregatedObject.GetController: IInterface;
    begin
      Result := IInterface(FController);
    end;
    Et cette différence semble avoir une influence certaine sur la manière dont fonctionne alors le ref counting...

    s'agirait t il d'un bug corrigé par codegear dans delphi 2007 ?

  12. #32
    Membre éclairé Avatar de Kaféine
    Homme Profil pro
    Inscrit en
    Avril 2007
    Messages
    569
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Avril 2007
    Messages : 569
    Points : 736
    Points
    736
    Par défaut
    Citation Envoyé par DenDemble
    Ca devrait fonctionner, or ce n'est plus le cas,
    Alors certes ton projet exemple fonctionne, mais il utilise une implementation de la classe TMonnayeur qui n'est pas Robuste et qui ne marche que si on l'utilise d'une certaine manière, ce qui a mon avis il faut a tout prix éviter...
    Du coup tu as trouvé la solution non? il suffit d'utiliser IInterface comme type de la référence. du coup pas d'obligation d'utiliser TAggregatedObject?!...
    Akim Merabet

  13. #33
    Membre du Club
    Profil pro
    Inscrit en
    Avril 2008
    Messages
    42
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2008
    Messages : 42
    Points : 51
    Points
    51
    Par défaut
    Citation Envoyé par Kaféine Voir le message
    Du coup tu as trouvé la solution non? il suffit d'utiliser IInterface comme type de la référence. du coup pas d'obligation d'utiliser TAggregatedObject?!...
    En effet, dans mon bout de code, une solution simple est de remplacer ISimpleCalculatrice par IInterface ou bien même IMonnayeur, et ca marche !

    Merci beaucoup Kaféine d'avoir consacré du temps à m'aider, mais en fait ce type de solution n'était pas ce que je recherchais :

    je me suis peut être mal exprimé lorsque j'ai proposé mon exemple de code qui ne marche pas, le revoici avec un commentaire qui clarifie un peu plus mon attente :
    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
     
    procedure TfrmTestInterface.CalculBtnClick(Sender: TObject);
    var calc:ISimpleCalculatrice; 
    // avec ISimpleCalculatrice, memoryleak !!
    // avec IInterface ou bien IMonnayeur : pas de memoryleak...
    // ce n'est pas normal car TMonnayeur référence toutes ces interfaces
        a,b:Currency;
    begin
      calc := TMonnayeur.create as ISimpleCalculatrice;
      a := StrToCurrDef(Edit1.Text, 0);
      b := StrToCurrDef(Edit2.Text, 0);
      calc.Ajouter(a);
      calc.Ajouter(b);
      Edit3.text := Format('%f', [calc.Valeur]);
    end;
    C'est volontairement que j'ai mis ISimpleCalculatrice, justement pour faire apparaitre le problème de l'implementation d'implements dans TMonnayeur.
    La solution que je cherchais était en fait une solution où le problème était corrigé en modifiant la classe TMonnayeur, et non pas une solution où le problème que j'ai mis en évidence est contourné.


    J'ai mis cherchait car en fait j'ai fini par trouver une solution à ce problème,
    et même plusieurs :

    la première solution évidente est bien sur d'utiliser TAggregatedObject, tout marche alors trés bien et je problème que j'avais mis en évidence est réglé...
    (d'ailleurs si ça interesse quelqu'un (et si Kaféine m'y autorise, car après tout c'est son exemple) je peut mettre en ligne une version remanièe du projet de Kaféine, qui montre l'utilisation de implements avec TAggregatedObject)
    Cependant comme je l'avais indiqué cette première solution ne me convient pas car alors on a une classe TSimpleCalculatrice qui ne sert qu'à faire des implements, et qui ne supportera pas automatiquement le ref counting, ce qui me gêne car le ref counting est une des raisons (parmi de nombreuses autres) pour lesquelles je n'utilise (désormais) que des références d'interfaces pour manipuler les instances de mes classes.

    J'ai donc fini par trouver une solution qui me convient mieux :
    j'ai créé un TAggregatableObject qui dérive de TAggregatedObject :
    Cette classe (et ses descendants) supporte le ref counting si
    on crée une instance de cette classe normalement (sans l'utiliser dans le cadre de implements)

    Cette même classe peut aussi être utilisée pour implements
    il faut alors la créer en utilisant le constructeur CreateImplementation,
    et à ce moment là l'instance se comporte comme une instance qui descendrait directement de TAggregatedObject.

    la voici :

    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
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
     
    unit UClass_AggregatableObject;
     
    interface
     
    type
      TAggregatableObject = class(TInterfacedObject)
      private
        FIsAggregated:boolean;
        FController: Pointer;  // weak reference to controller
        function GetController: IInterface;
      protected
        { IInterface }
        function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
        function _AddRef: Integer; stdcall;
        function _Release: Integer; stdcall;
      public
        // avec un create normal,
        // l'objet est créé avec du ref counting, il se comporte comme un vrai TInterfacedObject
        // ( on en profile pour rendre "virtual" le create de TObjet (bien utile..) )
        constructor Create; virtual;
        // l'objet est créé en étant associé à un Controller afin de permettre l'usage de Implements
        // pas de ref Counting, sa vie est liée à celle du controller.
        constructor CreateImplementation(const Controller: IInterface); virtual;
        property Controller: IInterface read GetController;
      end;
     
    implementation
     
    { TAggregatableObject }
    constructor TAggregatableObject.Create;
    begin
       FIsAggregated := false;
       FController := nil;
    end;
     
    constructor TAggregatableObject.CreateImplementation(const Controller: IInterface);
    begin
      FIsAggregated := true;
      // weak reference to controller - don't keep it alive
      FController := Pointer(Controller);
    end;
     
    function TAggregatableObject.GetController: IInterface;
    begin
      if FIsAggregated then
        Result := IInterface(FController)
      else
        Result := nil;
    end;
     
    function TAggregatableObject.QueryInterface(const IID: TGUID; out Obj): HResult;
    begin
      if FIsAggregated then
        Result := IInterface(FController).QueryInterface(IID, Obj)
      else begin
        // inherited ?
        if GetInterface(IID, Obj) then
          Result := 0
        else
          Result := E_NOINTERFACE;
      end;
    end;
     
    function InterlockedIncrement(var I: Integer): Integer;
    asm
          MOV   EDX,1
          XCHG  EAX,EDX
     LOCK XADD  [EDX],EAX
          INC   EAX
    end;
     
    function InterlockedDecrement(var I: Integer): Integer;
    asm
          MOV   EDX,-1
          XCHG  EAX,EDX
     LOCK XADD  [EDX],EAX
          DEC   EAX
    end;
     
    function TAggregatableObject._AddRef: Integer;
    begin
      if FIsAggregated then
        Result := IInterface(FController)._AddRef
      else
        Result := InterlockedIncrement(FRefCount);
    end;
     
    function TAggregatableObject._Release: Integer;
    begin
      if FIsAggregated then
        Result := IInterface(FController)._Release
      else begin
        Result := InterlockedDecrement(FRefCount);
        if Result = 0 then Destroy;
      end;
     
    end;
     
    end.
    En fait moi aussi j'ai découvert implements grace à ce thread,
    donc tout commentaire sur cette classe (même négatif) sera apprécié et bienvenu, car, après l'avoir testée un peu, je vais surement finir par l'utiliser dans mes projets et je ne voudrait pas qu'elle contienne des erreurs de conception.

  14. #34
    Membre éclairé Avatar de Kaféine
    Homme Profil pro
    Inscrit en
    Avril 2007
    Messages
    569
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Avril 2007
    Messages : 569
    Points : 736
    Points
    736
    Par défaut
    Citation Envoyé par DenDemble
    En effet, dans mon bout de code, une solution simple est de remplacer ISimpleCalculatrice par IInterface ou bien même IMonnayeur, et ca marche !
    en gros toute les interfaces de l'objet à l'exception de ou des interface(s) implémentée(s) par délégation.


    Citation Envoyé par DenDemble
    d'ailleurs si ça interesse quelqu'un (et si Kaféine m'y autorise, car après tout c'est son exemple) je peut mettre en ligne une version remanièe du projet de Kaféine, qui montre l'utilisation de implements avec TAggregatedObject
    même pas besoin de demander et en plus ça m'interesse

    Citation Envoyé par DenDemble
    car alors on a une classe TSimpleCalculatrice qui ne sert qu'à faire des implements
    je comprend pas trop ce que tu veux dire...
    rien n'empeche d'utiliser cette classe directement!

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    procedure TfrmTestInterface.Button4Click(Sender: TObject);
    var
      SC: ISimpleCalculatrice;
    begin
      SC := TSimpleCalculatrice.Create;
      SC.Valeur := 10;
      SC.Ajouter(10);
      Showmessage(CurrToStr(SC.Valeur));
    end;
    l'implements ici c'est pour eviter de réécrire l'implementation de l'interface ISimpleCalculatrice afin que le monnayeur la support .

    a la limite, si le monnayeur implemente ISimpleCalculatrice sans délégation, alors pas de probleme.

    de facon naturelle dans mon esprit, FMonnayeur de la fiche principal est du type IMonnayeur, mais maintenant je sais qu'il ne doit absolument pas être du type ISimpleCalculatrice, c'est à dire l'interface par délégation.
    Akim Merabet

  15. #35
    Membre éclairé Avatar de Kaféine
    Homme Profil pro
    Inscrit en
    Avril 2007
    Messages
    569
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Avril 2007
    Messages : 569
    Points : 736
    Points
    736
    Par défaut
    Citation Envoyé par Kaféine
    je comprend pas trop ce que tu veux dire...
    rien n'empeche d'utiliser cette classe directement!
    autant pour moi, j'ai compris, tu parlais avec TAggregatedObject...
    Akim Merabet

  16. #36
    Membre du Club
    Profil pro
    Inscrit en
    Avril 2008
    Messages
    42
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2008
    Messages : 42
    Points : 51
    Points
    51
    Par défaut
    Citation Envoyé par Kaféine Voir le message
    en gros toute les interfaces de l'objet à l'exception de ou des interface(s) implémentée(s) par délégation.
    Exactement, ce qui revient a dire que l'interface implémentée par délégation dans ton exemple initial est mal (en fait partiellement) implementée :

    Dans ton exemple, si on utilise l'aspect ISimpleCalculatrice (via un as ou via QueryInterface ou via supports)
    d'un TMonnayeur créé initialement avec une ref d'interface autre, ca fonctionne

    Mais c'est quand on veut utiliser directement ISimpleCalculatrice que ca ne marche pas.

    En pièce jointe voici la version avec TAggregatedObject.
    le TMonnayeur de la fiche Main est créé avec une ref vers l'interface ISimpleCalculatrice et là ça fonctionne désormais...
    (dans l'exemple j'ai commenté tous les changements que j'ai fait par rapport à l'exemple original)

    Par contre, le code suivant ne marche désormais plus (memory leak).
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    procedure TfrmTestInterface.Button4Click(Sender: TObject);
    var
      SC: ISimpleCalculatrice;
    begin
      SC := TSimpleCalculatrice.Create;
      SC.Valeur := 10;
      SC.Ajouter(10);
      Showmessage(CurrToStr(SC.Valeur));
    end;
    et ce à cause de l'utilisation de TAggregatedObject.

    Si je n'ai pas fait d'erreur, il suffit d'inclure l'unité UClass_AggregatableObject (voir mon post précédent)
    dans uintf.pas et de changer 2 autres ligne de cette unité :

    utiliser TAggregatableObject au lieu de TAggregatedObject
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
      TSimpleCalculatrice = class(TAggregatableObject, ISimpleCalculatrice)
    et plus bas, dans le create de TMonnayeur, utiliser le constructeur dédié
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
      FSimpleCalculatrice := TSimpleCalculatrice.CreateImplementation(self);
    pour que tout fonctionne :
    - un implements qui permet d'utiliser réellement le ISimpleCalculatrice de TMonnayeur
    - Une classe TSimpleCalculatrice réutilisable


    Maintenant, que j'y vois un peu plus clair sur l'utilisation "technique" de implements, une question fondamentale reste posée :
    en conception quand et où pourrais-je utiliser cette technique de délégation
    sans risquer de créer des erreurs de conception.

    Comme l'a dit Kaféine,
    a la limite, si le monnayeur implemente ISimpleCalculatrice sans délégation, alors pas de probleme.
    En effet on a peut être travaillé sur un exemple où finalement l'usage de implements n'était pas fondamentalement nécessaire, mais cela a eu au moins le mérite de soulever des problèmes d'ordre technique..

    Donc c'est vrai (et je pense aux remarques de Paul Toth et Frank Soriano) qu'un exemple plus pertinent sur l'utilisation de cette technique serait je bienvenu.. je vais y réflechir.. si en attendant qqun a des idées..
    Fichiers attachés Fichiers attachés

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

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

    Informations forums :
    Inscription : Novembre 2002
    Messages : 8 964
    Points : 28 445
    Points
    28 445
    Par défaut
    Citation Envoyé par DenDemble Voir le message
    Je n'ai pas encore analysé l'exemple, mais j'ai déjà une première remarque :

    On n'a pas la même version de Delphi ?

    Moi j'ai Delphi 2007, et dans system.pas TAggregatedObject n'est pas implémenté de la même manière que dans l'exemple :
    en effet je suis sous Delphi 6 Personal Edition...mais mon code ne reprend pas le code Borland

    j'aurais peut-être du prendre un autre nom de classe pour éviter la confusion, mais l'idée était de montrer pourquoi il y a un problème (double AddRef sur la classe et sa propriété et un seul Release) et comment TAggregatedObject le corrige

    j'ai toujours considéré qu'il ne fallait comprendre les mécanismes en jeu pour savoir ce que l'on fait. TInterfacedObject et TAggregatedOjbect ne sont pas des objets magiques...tout comme la libération automatiquement des interfaces n'est pas magique, cela suis une logique rigoureuse qu'il est bon de connaitre
    Developpez.com: Mes articles, forum FlashPascal
    Entreprise: Execute SARL
    Le Store Excute Store

  18. #38
    Membre éclairé Avatar de Kaféine
    Homme Profil pro
    Inscrit en
    Avril 2007
    Messages
    569
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Avril 2007
    Messages : 569
    Points : 736
    Points
    736
    Par défaut
    Citation Envoyé par DenDemble
    Donc c'est vrai (et je pense aux remarques de Paul Toth et Frank Soriano) qu'un exemple plus pertinent sur l'utilisation de cette technique serait je bienvenu.. je vais y réflechir.. si en attendant qqun a des idées..
    effectivement un exemple pertinent de l'usage de l'implements serais interessant.
    pour moi, l'implements, c'est juste une méthode rapide pour éviter de réécrire les methodes de l'interface.

    je pense que l'on peut se passer de l'implements, en faisant par exemple ceci

    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
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
     
    IFoo = interface
        [GUID]
        procedure Foo;
      end;
     
      TFoo = class(TInterfacedObject, IFoo)
      public
        procedure Foo;
      end;
     
      ITest = interface
        [GUID]
        procedure Test;
      end;
     
      TTest = class(TInterfacedObject, ITest, IFoo)
      private
        FFoo: IFoo;
      public
        constructor Create;
        procedure Test;
        procedure Foo;
      end;
     
    { TFoo }
     
    procedure TFoo.Foo;
    begin
      Showmessage('Foo');
    end;
     
    { TTest }
     
    constructor TTest.Create;
    begin
      FFoo := TFoo.Create;
    end;
     
    procedure TTest.Foo;
    begin
      FFoo.Foo;
    end;
     
    procedure TTest.Test;
    begin
      Showmessage('Test');
    end;
    Akim Merabet

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

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

    Informations forums :
    Inscription : Novembre 2002
    Messages : 8 964
    Points : 28 445
    Points
    28 445
    Par défaut
    on doit pouvoir se passer des implements c'est sur...mais sans avoir vraiment manipuler les interfaces, je me dis que dans un truc comme DirectX par exemple, ou chaque nouvelle version apporte son lot de nouvelles interfaces tout en assurant une compatibilité ascendante, pouvoir déporter une ancienne inteface dans un implements ça doit faciliter la vie (je parle du côté de ceux qui programment DirectX, pas de ceux qui l'utilise)

    quelque chose du genre

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    type
     TInterfaceV2=class(TInterfacedObject,IInterfaceV2)
     ...
      public
       property Version1:IInterfaceV1 read GetInterfaceV1 implements IInterfaceV1;
     end;
    Developpez.com: Mes articles, forum FlashPascal
    Entreprise: Execute SARL
    Le Store Excute Store

  20. #40
    Membre éclairé Avatar de Kaféine
    Homme Profil pro
    Inscrit en
    Avril 2007
    Messages
    569
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Avril 2007
    Messages : 569
    Points : 736
    Points
    736
    Par défaut
    Citation Envoyé par Paul TOTH
    DirectX par exemple, ou chaque nouvelle version apporte son lot de nouvelles interfaces tout en assurant une compatibilité ascendante
    le versionning au niveau des interfaces directx est a mon avis fait pour que des applications DX8 par exemple continue à fonctionner même
    avec DX9 installé. En fait lors de l'installation de DX9, DX8 n'est pas desinstallé et ces interfaces, avec leur GUID propre reste dispo. maintenant effectivement peut etre qu'il utilise des fonctionnalités de version antérieur dans l'implementation des interfaces.
    mais du coup, il l'utilise en interne et l'objet ne doit pas supporte l'ancienne interface. je pense qu'il utilise une technique en evitant l'implements. mais bon tout cela reste dans le domaine de la spéculation

    par exemple:

    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
    39
    40
    41
    42
    43
    44
     
     
      IIntfV1 = interface
        procedure UnTruc;
      end;
     
      TImplV1 = class(TInterfacedObject, IIntfV1)
      public
        procedure UnTruc;
      end;
     
      IIntfV2 = interface
        procedure UnTruc;
      end;
     
      TImplV2 = class(TInterfacedObject, IIntfV2)
      private
        FIntfV1: IIntfV1;
      public
        constructor Create;
        procedure UnTruc;
      end;
     
    {...}
     
    { TImplV1 }
     
    procedure TImplV1.UnTruc;
    begin
      ShowMessage('Un truc v1');
    end;
     
    { TImplV2 }
     
    constructor TImplV2.Create;
    begin
      FIntfV1 := TImplV1.Create;
    end;
     
    procedure TImplV2.UnTruc;
    begin
      FIntfV1.UnTruc;  // ici recuperation d'un traitement V1
      ShowMessage('Un truc v2'); // traitement V2
    end;
    avec l'implements, ca oblige que l'objet supporte l'interface.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
     
    type
     TInterfaceV2=class(TInterfacedObject,IInterfaceV2, IInterfaceV1) //<-- support de l'interface V1
     ...
      public
       property Version1:IInterfaceV1 read GetInterfaceV1 implements IInterfaceV1;
     end;

    or je crois pas qu'un application peut supporter DX8 et DX9 en meme temps. mais bon je me trompe peut etre.
    Akim Merabet

Discussions similaires

  1. [Algorithmes génétiques] Limites ?
    Par laclac dans le forum Intelligence artificielle
    Réponses: 2
    Dernier message: 21/03/2006, 10h46
  2. Les limites de wget
    Par djibril dans le forum Applications et environnements graphiques
    Réponses: 10
    Dernier message: 23/02/2006, 11h20
  3. Les limites d'ext3
    Par GLDavid dans le forum Administration système
    Réponses: 5
    Dernier message: 05/12/2005, 11h32
  4. Réponses: 2
    Dernier message: 13/10/2005, 19h04
  5. Quelles sont les limites de INTERBASE 7.5 ?
    Par lio33 dans le forum InterBase
    Réponses: 1
    Dernier message: 21/07/2005, 12h54

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