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 :

Interfaces, Pattern Observer


Sujet :

Langage Delphi

  1. #1
    Futur Membre du Club
    Profil pro
    Inscrit en
    Décembre 2003
    Messages
    7
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2003
    Messages : 7
    Points : 5
    Points
    5
    Par défaut Interfaces, Pattern Observer
    Bonjour a tous,
    je suis en train de refondre un projet en essayant de le restructurer un peu, et au passage appliquait le fabuleux pattern observer.... mais voila, je m'oppose à un problème incompréhensible: mes interfaces ne semblent pas être reconnues, et je me confronte à des pointer exceptions.

    Voici globalement mon observateur (en code simplifié pour faciliter la lecture)
    [si jamais qqun souhaite le vrai code pour tenter de résoudre le problème, pas de soucis, je le mettrais]

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    class Oservateur {
       function add ( interface IObjetObservable){
          observerList.add (IObjetObservable)
       }
       function notify (eventType typeEvenement; event CeQuiCestPasse){
          for i:=0 to observerList.count-1 do begin
             if  IObjetObservable (observerList.items[I]).observe (typeEvenement) then
                IObjetObservable (observerList.items[I]).perform  (CeQuiCestPasse);
             enf
          end
       }
    }
    Bon, globalement, j'ai des types d'événements et des observers par type d'événement.
    Lorsqu'un événement est déclenché, tous les observeurs sont appelés avec en paramètre ce qui c'est passé.

    Pour les observateur, je les fais implémenter l'interface IObjetObservateur.

    Tout ce passe bien quand mon objet observateur est déclaré de la sorte:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    class Objet = class (TInterfacedObject, IObjetObservateur)
    Mais tout ce passe moins bien lorsque je décide qu'un TForm par exemple puisse observer:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    class FormX = class (TForm, IObjetObservateur)
    Dans le dernier cas, il semble que les méthodes d'implémentation de FormX ne soient jamais appelés......

    Dans le deboggeur, la ligne est "traversée", mais pas exécutée DANS l'observateur.

    Bon, maintenant, le problème sous un autre angle:
    Mon besoin est le suivant:

    Je veux déclarer une interface qui soit implémentable par tous mes objets (quels qu'ils soient TForm, tout neuf, TCombo, ..., ...).
    Une fonction capable de conserver une liste d'objets implémentant cette interface.
    [prototype: procedure add (objetI : INomInterface)]

    La possibilité de parcourir ces objets et de les manipuler via cette interface.....
    [liste.items[X].appelFonctionDeLInterface (avec des paramètres);]

    Merci de votre aide, je ne vois plus comment faire.
    [je vois très bien en java, en python, en php, ..... mais en delphi...... j'arrive pas]

  2. #2
    Membre du Club Avatar de philemon_siclone
    Inscrit en
    Septembre 2003
    Messages
    67
    Détails du profil
    Informations forums :
    Inscription : Septembre 2003
    Messages : 67
    Points : 67
    Points
    67
    Par défaut
    Je sais pas si ça peut t'aider; mais pour un projet j'ai implementé le mecanisme suivant :
    Certains de mes controls (combos, TEdit, etc.) implementaient une interface IValidableControl (celle-ci définissaient 2 methodes : heavyValidate() et lightValidate()). Quand dans une fenêtre je voulais valider tout les controles validables je faisais simplement :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    var
        i : integer;
      vc : IValidableControl;
    begin
    for i := 0 to ComponentCount-1 do
      begin
        if Components[i].GetInterface(IValidableControl, vc) then
          vc.HeavyValidate;
      end;
    Cordialement,

    PS : j'ai aussi pas mal de problèmes avec les interfaces en Delphi. Notamment, je pense, parce qu'il y a une notion d'instance d'interface en Delphi (et de comptage par reference); ce qui n'existe pas en java.

  3. #3
    Futur Membre du Club
    Profil pro
    Inscrit en
    Décembre 2003
    Messages
    7
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2003
    Messages : 7
    Points : 5
    Points
    5
    Par défaut
    Horreur...... encore plus incompréhensible.

    Le code suivant:

    considérons
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    type TMaClass = class (TInterfacedObject, IMonInterface)
    end;
     
    var
       maClass : TMaClass
     
    implementation
    ....
     
    Maintenant dans le code
    maClass = TMaClass.Create ();//la variable "globale" maClass
    list := TList.Create ();
    list.add (maClass);
    //et la, le destructeur de maClass est appelé ??????
    [Balise [code] rajoutée par Nono40]


    [le cas est résumé, mais c'est vraiment ça ?]
    Note: j'utilise Kylix..... ceci explique peut être cela ?

  4. #4
    Futur Membre du Club
    Profil pro
    Inscrit en
    Décembre 2003
    Messages
    7
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2003
    Messages : 7
    Points : 5
    Points
    5
    Par défaut
    Citation Envoyé par philemon_siclone
    PS : j'ai aussi pas mal de problèmes avec les interfaces en Delphi. Notamment, je pense, parce qu'il y a une notion d'instance d'interface en Delphi (et de comptage par reference); ce qui n'existe pas en java.
    C'est le moins qu'on puisse dire :-)
    Merci pour ton aide, j'investigue la piste queryInterface....
    il faut visiblement que je lui donne une identité ?
    bref, j'essaye ça de suite.

    note pour plus tard: le pascal n'est pas fait pour les interfaces, ni pour les héritages multiples..... :-(

  5. #5
    Membre chevronné
    Avatar de Pierre Castelain
    Inscrit en
    Avril 2002
    Messages
    523
    Détails du profil
    Informations forums :
    Inscription : Avril 2002
    Messages : 523
    Points : 1 943
    Points
    1 943
    Par défaut
    n dirait que tu a raté un chapitre sur le fonctionnement des interfaces COM...
    Lorsqu'une instance de coclasse est créée, son compteur de référence est passé à 1. A chaque affectation de l'instance dans une variable, le compteur est incrémenté. Pour chaque libération de variable, le compteur est décrémenté. Lorsqu'il arrive à zéro, l'instance est libérée.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    MaClasse:= TMaClasse.Create; // Compteur = 1
    LaClasse:= MaClasse; // Compteur = 2
    MaClasse:= nil; // Compteur = 1
    LaClasse:= nil; // Compteur = 0, instance libérée
    Ce mécanisme est valable pour toutes les variables de "type instance", mais ce n'est pas le cas pour les pointeurs (par exemple). Ce qui explique le comportement que tu as repéré. Lorsque tu fait :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    list.add (maClass);
    le compteur de référence n'est PAS incrémenté car l'argument est de type pointeur.

  6. #6
    Futur Membre du Club
    Profil pro
    Inscrit en
    Décembre 2003
    Messages
    7
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2003
    Messages : 7
    Points : 5
    Points
    5
    Par défaut
    En fait, mon soucis est que je ne souhaite pas particulièrement utiliser des interfaces COM, mais simplement le concept d'interface (Tout court).
    Il est vrai que niveau documentation, j'ai beau chercher, mais je ne trouve pas.

    La seule chose que je vois, c'est le coté: pour pallier à l'héritage multiple, utilisez les interfaces....
    Ok, je veux bien, c'est ce que j'essaye de faire (comme je le ferais en Java disais-je). Nulle part je ne souhaite utiliser des interfaces COM, juste des interfaces "normales".

    De même, je ne supprime pas explicitement la référence de la variable.... donc je ne comprends pas pourquoi ce dernier est "déréférencé".
    Je me suis aussi posé la question, tout de même. De la sorte, j'ai essayé avec le code suivant:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    var
       copy : Type;
    begin
       globale := Type.Create ();
       copy := globale;
     
       liste.add (copy);
       //ploumf, je rentre dans le destructeur.
    En plus, j'initialise la variable globale X à une valeur, à l'intérieur d'une fonction. La portée étant supérieure, je ne vois pas pourquoi la variable serait "déréférencée" à la sortie de la fonction.

    Enfin, .... j'ai beau chercher dans mon code, je ne trouve pas.

    Je me suis résigné à faire des objets abstraits, et à implémenter des sortes de "télécommandes" pour les objets qui auraient bénéficié d'une bonne vieille interfaces ou d'un héritage multiple. [a savoir que j'ai un autre problème bizarre de quittage d'appli violent, sans message d'erreur.... mais bon, comme je commençais à être un peu perplexe, j'ai préféré arrêter la et reprendre à tête reposée]

    Maintenant, je suis premier à accepter mon erreur si qq est capable de mon montrer un code qui tourne pour implémenter le concept évoqué.

    Le projet en question: http://phpside.org pour son passage en version linux.
    Le code est dispo à quiquonque en fait la demande.

    Merci pour votre aide :-)

  7. #7
    Membre à l'essai
    Inscrit en
    Avril 2002
    Messages
    20
    Détails du profil
    Informations forums :
    Inscription : Avril 2002
    Messages : 20
    Points : 20
    Points
    20
    Par défaut
    Une solution au problème du comptage de références est de créer sa propre class TInterfacedObject qui ne fait rien dans AddRef et Release.

    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
     
    function TMyInterfacedObject.QueryInterface(const IID: TGUID; out Obj): HResult;
    const
      E_NOINTERFACE = $80004002;
    begin
      if GetInterface(IID, Obj) then Result := 0 else Result := E_NOINTERFACE;
    end;
     
    function TMyInterfacedObject._AddRef: Integer;
    begin
            result:=-1;
    end;
     
    function TMyInterfacedObject._Release: Integer;
    begin
            result:=-1;
    end;

  8. #8
    Futur Membre du Club
    Profil pro
    Inscrit en
    Décembre 2003
    Messages
    7
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2003
    Messages : 7
    Points : 5
    Points
    5
    Par défaut
    Ok...... merci :-) je vais essayer ça dès que possible.

    Pour être sur d'avoir bien compris, j'implémente une classe TInterfaceDeBase qui hérite de TInterfacedObject en écrasant les méthodes "références" ?

    cad
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    TInterfaceDeBase = class (TInterfacedObject)
       code.
    end;
    Une question toutefois : avec cette méthode de "court-circuit", n'existe t - il pas un risque de "fuite mémoire" ?

    Dernière question et j'arrête
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    const
      E_NOINTERFACE = $80004002;
    Puis-je utiliser cette valeur ? y'a t-il des plages de valeurs à éviter pour mes futures interfaces ?

    Si tout cela résouds mon problème, j'appliquerais avec plaisir le [Résolu] sur le titre de ce post

  9. #9
    Futur Membre du Club
    Profil pro
    Inscrit en
    Décembre 2003
    Messages
    7
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2003
    Messages : 7
    Points : 5
    Points
    5
    Par défaut
    Bien,
    n'arrivant pas a obtenir le comportement voulu avec une interface, et souhaitant avancer dans mon projet, je me suis résolu à créer des "observateur" dédié par types d'éléments (uniquement pour ceux héritant déja d'autres objets).

    La solution n'est pas des plus belles, mais reste fonctionnel et peu couteuse en temps de développement.

    Si un jour je me sens d'attaque pour retenter l'expérience, le retour à la normale ne sera pas trop couteux.

    Voici en résumé la solution implémentée:

    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
    class TObservateur
       public
          function methodeEcoute ();
          //....
    end;
     
    {
    Une classe qui aurais aimer être capable d'observer elle même
    héritant déja d'un objet
    }
    class TAimeraisObserver = class (TForm)
       public
          function methodeExecute ();
    end;
     
    {
    Une "télécommande"pour le vrai observateur.
    }
    class TRemoteObservateur = class (TObservateur)
       public
          constructor Create (implementationObservateur : TAimeraisObserver);
          function methodeExecute ();//le code est == Result := implementation.methodeExecute ()
    end;
     
    {
    Voici le cas pour un observateur classique.
    }
    class TObserverNormal = class (TObservateur)
    //implémentation normale de l'écoute
    end;
    Tout ceci fonctionne bien, je vais le laisser tel quel en attendant mieux.
    [j'ai un peu honte, mais bon ]

    Merci à tous pour votre aide.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [Conception] Design Pattern Observer Java
    Par jeb001 dans le forum Général Java
    Réponses: 4
    Dernier message: 02/05/2007, 23h43
  2. [Pattern] Marker Interface Pattern
    Par Fr@ncky dans le forum Langage
    Réponses: 8
    Dernier message: 20/12/2006, 11h18
  3. Pattern Observer over CORBA ?
    Par swirtel dans le forum CORBA
    Réponses: 4
    Dernier message: 15/09/2006, 14h03
  4. Réponses: 2
    Dernier message: 24/08/2006, 22h39
  5. [Observateur] Précisions sur le design pattern Observer [UML]
    Par joquetino dans le forum Design Patterns
    Réponses: 2
    Dernier message: 07/10/2004, 22h35

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