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

VBA Discussion :

Polymorphisme, implémentation [Débat]


Sujet :

VBA

  1. #1
    Membre émérite

    Profil pro
    Inscrit en
    février 2005
    Messages
    1 749
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : février 2005
    Messages : 1 749
    Points : 2 312
    Points
    2 312
    Par défaut Polymorphisme avec VBA: implémentation d'interface
    Bonjour,

    En fait le fil de messages originel est à rechercher sur le forum Access/VBA Access qui évoquait la problématique de l'héritage pour les classes développées en VBA: Héritage, possible ou non?

    Donc la discussion a quelque peu dévié sur la question du polymorphisme, et s'est retrouvé déplacée sur le forum Général VBA.

    _____---====OOOOO====---

    Au risque de déborder un peu sur le sujet originel, je souhaite préciser comment on met en œuvre le polymorphisme en VB/VBA.

    Citation Envoyé par Pierre Fauconnier Voir le message
    Ce ne serait pas l'inverse ? ... Implements permet "une sorte" d'héritage, mais pas le polymorphisme... (enfin, c'est ce qu'il me semble...)
    D'abord il faut s'entendre sur la signification de polymorphisme.
    Aussi, je me reposerai sur Wikipédia avec un court extrait ci-dessous et la suite sur la page de Wikipédia illustrée par un exemple:
    Citation Envoyé par Wikipédia
    En informatique, le polymorphisme est l'idée d'autoriser le même code à être utilisé avec différents types, ce qui permet des implémentations plus abstraites et générales.
    Je reprends l'exemple de la page de Wikipédia (merci de vous y reporter) en l'adaptant au VB/VBA.

    Une classe-interface cForme décrit les méthodes à implémenter pour toutes les "formes" géométriques:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    Option Explicit
     
    Public Function Aire() As Double
        Aire = 0
    End Function
    Une classe cCarré décrit les formes de type Carré et implémente les méthodes d'une "forme" géométrique.

    L'utilisation du mot-clé Implements (dans la partie déclaration du module de classe) spécifie qu'une classe implémente l'interface publique (méthodes et propriétés) d'une autre classe.
    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
    Option Explicit
     
    Implements cForme
     
    Private p_nCôté As Double
     
    Private Function cForme_Aire() As Double
        cForme_Aire = p_nCôté * p_nCôté
    End Function
     
    Public Property Get Côté() As Double
        Côté = p_nCôté
    End Property
     
    Public Property Let Côté(n As Double)
        p_nCôté = n
    End Property
    Une classe cCercle décrit les formes de type Cercle et implémente les méthodes d'une "forme" géométrique:
    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
    Option Explicit
     
    Implements cForme
     
    Private p_nRayon As Double
     
    Private Function cForme_Aire() As Double
        cForme_Aire = CDbl(3.1415926535) * p_nRayon * p_nRayon
    End Function
     
    Public Property Get Rayon() As Double
        Rayon = p_nRayon
    End Property
     
    Public Property Let Rayon(n As Double)
        p_nRayon = n
    End Property
    Dans un module de code, on spécifie la fonction AireTotal() qui reçoit en paramètre une collection d'objets "formes" et retourne la somme des aires de ces objets.
    C'est ici que le polymorphisme rentre en jeu puisque, selon le type de "forme", la fonction fait toujours appel à la bonne méthode de calcul Aire(). Tout type de "forme" géométrique qui implémente la classe/interface cForme peut être ajouté sans nécessiter une modification de la fonction AireTotal().
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    Public Function AireTotal(collFormes As Collection) As Double
        Dim oForme As cForme
        Dim nTotal As Double
     
        nTotal = 0
     
        For Each oForme In collFormes
            ' la fonction "sait" automatiquement quelle méthode Aire() appeler
            nTotal = nTotal + oForme.Aire()
        Next oForme
     
        AireTotal = nTotal
    End Function
    Enfin, on peut aussi coder une procédure pour tester tout ça:
    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
    Public Sub TestFormes()
        Dim oCarré As New cCarré
        Dim oCercle As New cCercle
        Dim collFormes As New Collection
        Dim nTotal As Double
     
        oCarré.Côté = 3.4
        oCercle.Rayon = 5.1
     
        collFormes.Add oCarré
        collFormes.Add oCercle
     
        nTotal = AireTotal(collFormes)
     
        Debug.Print nTotal
    End Sub
    A l'usage, l'implémentation d'interface permet:
    (1) de coder des procédures "génériques" qu'il ne sera pas nécessaire de modifier pour prendre en compte de nouveaux "sous-types" (exemple la fonction AireTotal()),
    (2) d'obtenir un code plus robuste parce que les appels de méthodes sont vérifiés à la compilation (liaison dynamique "late binding" mais avec la rigueur du contrôle de type).

    Merci aux courageux et curieux qui ont lu jusqu'au bout.
    _

  2. #2
    Responsable
    Office & Excel

    Avatar de Pierre Fauconnier
    Homme Profil pro
    Formateur et développeur informatique indépendant
    Inscrit en
    novembre 2003
    Messages
    14 543
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : Formateur et développeur informatique indépendant
    Secteur : Enseignement

    Informations forums :
    Inscription : novembre 2003
    Messages : 14 543
    Points : 40 101
    Points
    40 101
    Billets dans le blog
    58
    Par défaut
    Salut...

    Bah... Tant pis pour le débordement...

    Dans les exemples que tu proposes, je ne vois pas de polymorphisme (... le même code à être utilisé avec différents types...) puisque les classes Carré et Cercle utilisent le même type (même (absence de) paramètre..., même type renvoyé)...
    Pour moi, le polymorphisme, c'est d'avoir deux fonctions de même nom dans une même classe, mais avec la possibilité de passer des paramètres différents
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    function Aire(Cote as double) as double
        ...
    end function
     
    function Aire(Longueur as double, Largeur as double) as double
        ....
    end function
    Ce cas est impossible en vba car pas de polymorphisme, alors qu'il est possible en vb.net.

    Donc, pour moi, dans ton exemple, on met bien un "pseudo"- héritage dont je ne vois par ailleurs pas vraiment l'intérêt...
    "Plus les hommes seront éclairés, plus ils seront libres" (Voltaire)
    ---------------
    Mes remarques et critiques sont purement techniques. Ne les prenez jamais pour des attaques personnelles...
    Une fois pour toutes, je donne mon avis. Je ne vais pas le répéter à chaque message...
    Si je propose une solution générique sur votre solution spécifique, c'est parce que, fainéant de nature, je privilégie le réutilisable...
    Le VBA ne palliera jamais une mauvaise conception de classeur ou un manque de connaissances des outils natifs d'Excel...
    Vous souhaitez rédiger pour DVP? Contactez-moi
    VBA pour Excel? Pensez D'ABORD en EXCEL avant de penser en VBA...
    ---------------

  3. #3
    Membre émérite

    Profil pro
    Inscrit en
    février 2005
    Messages
    1 749
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : février 2005
    Messages : 1 749
    Points : 2 312
    Points
    2 312
    Par défaut
    Bonjour,
    Citation Envoyé par Pierre Fauconnier Voir le message
    Pour moi, le polymorphisme, c'est d'avoir deux fonctions de même nom dans une même classe, mais avec la possibilité de passer des paramètres différents
    [...]
    Ce cas est impossible en vba car pas de polymorphisme, alors qu'il est possible en vb.net.

    Donc, pour moi, dans ton exemple, on met bien un "pseudo"- héritage dont je ne vois par ailleurs pas vraiment l'intérêt...
    En fait tu évoques la technique de surcharge de fonction (ou d'opérateur) qui n'est pas particulièrement liée aux langages à/orientés objet. On peut aussi la retrouver dans certains langages fonctionnels ou procéduraux.

    Tu assimiles «surcharge de fonction» et «polymorphisme», et c'est une confusion que l'on voit fréquemment sur l'internet.
    Dans Wikipédia en anglais l'article sur le polymorphisme expose les choses plus précisément en distinguant différentes formes de polymorphisme:
    • ad-hoc polymorphism,
    • parametric polymorphsim d'où découle le subtyping polymorphism (ou encore inclusion polymorphism).


    La surcharge de fonction relève de l'ad-hoc polymorphism.

    L'exécution dynamique de méthode relève du subtyping polymorphism (c'est l'exemple que j'ai donné).

    Une différence essentielle entre surcharge et exécution dynamique peut s'expliquer quand on considère l'étape de compilation d'un programme.

    En ce qui concerne la surcharge, un compilateur peut déterminer la fonction à appeler au moyen des types des paramètres qui sont déjà connus à la compilation: la liaison est établie dès la compilation du code.

    En ce qui concerne une "fonction polymorphe" (comme la fonction AireTotal()) le compilateur ne peut pas connaître la bonne méthode (ici la méthode Aire()) qui sera exécutée car le type réel (la "forme" géométrique) ne sera connu qu'à l'exécution.
    _

  4. #4
    Responsable
    Office & Excel

    Avatar de Pierre Fauconnier
    Homme Profil pro
    Formateur et développeur informatique indépendant
    Inscrit en
    novembre 2003
    Messages
    14 543
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : Formateur et développeur informatique indépendant
    Secteur : Enseignement

    Informations forums :
    Inscription : novembre 2003
    Messages : 14 543
    Points : 40 101
    Points
    40 101
    Billets dans le blog
    58
    Par défaut
    Salut...

    D'accord avec toi. En faisant des tests, j'ai compris mon mélange entre les deux notions... Merci pour les explications détaillées.

    Cela étant, quel est l'intérêt de ce type de polymorphisme en VBA? Dans la pratique, je ne vois pas trop en quoi cela peut aider, si ce n'est à "généraliser" des propriétés "communes" à différentes classes. Si l'intérêt s'arrête là, je trouve que c'est un peu lourd à mettre en place, non?

    Ton avis m'intéresse. Merci
    "Plus les hommes seront éclairés, plus ils seront libres" (Voltaire)
    ---------------
    Mes remarques et critiques sont purement techniques. Ne les prenez jamais pour des attaques personnelles...
    Une fois pour toutes, je donne mon avis. Je ne vais pas le répéter à chaque message...
    Si je propose une solution générique sur votre solution spécifique, c'est parce que, fainéant de nature, je privilégie le réutilisable...
    Le VBA ne palliera jamais une mauvaise conception de classeur ou un manque de connaissances des outils natifs d'Excel...
    Vous souhaitez rédiger pour DVP? Contactez-moi
    VBA pour Excel? Pensez D'ABORD en EXCEL avant de penser en VBA...
    ---------------

  5. #5
    Membre émérite

    Profil pro
    Inscrit en
    février 2005
    Messages
    1 749
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : février 2005
    Messages : 1 749
    Points : 2 312
    Points
    2 312
    Par défaut
    Citation Envoyé par Pierre Fauconnier Voir le message
    Cela étant, quel est l'intérêt de ce type de polymorphisme en VBA? Dans la pratique, je ne vois pas trop en quoi cela peut aider, si ce n'est à "généraliser" des propriétés "communes" à différentes classes. Si l'intérêt s'arrête là, je trouve que c'est un peu lourd à mettre en place, non?

    Ton avis m'intéresse. Merci
    Tout d'abord, l'implémentation d'interface est un des mécanismes fondamentaux de l'architecture COM de Windows, permettant l'intégration de nouveaux types d'objets à l'intérieur de cette infrastructure complexes.
    C'est toujours ce même mécanisme qui permet d'étendre les fonctionnalités de l'IDE VB/VBA.

    Pour ma part, je m'en suis beaucoup servi dans le cadre de projets complexes en VBA/Access.
    En effet, il y a un moment où un grand nombre de formulaires rend difficile (problématique) l'exécution d'une application Access.

    J'ai donc "sorti" et factorisé un maximum de codes communs aux formulaires pour coder des fonctions/procédures polymorphes.
    Ceci m'a amené à spécifier une classe-interface cFormApp listant les méthodes qu'un formulaire devait implémenter (le mot-clé Implements est autorisé dans le module de code d'un formulaire ou d'un état).
    Cette classe-interface était alors utilisée dans mes fonctions/procédures polymorphes.

    Ensuite dans les applications Access, j'ai rattaché les fonctions polymorphes aux barres de menus et d'outils. La première tâche de la fonction polymorphe est de récupérer l'objet en cours (le formulaire qui a le focus) puis d'y appliquer le reste du code.

    Cette méthode m'a permis:
    (1) de développer des gros projets qui se seraient essoufflés à cause du volume formulaire/code (nombre de formulaires divisé par 3 voire 4),
    (2) de développer dans de bonnes conditions grâce à une meilleure robustesse du code,
    (3) de gérer au mieux l'évolution des applications:
    ___(3.a) rapidité pour l'ajout d'un nouveau type de formulaire,
    ___(3.b) ajout de nouvelles fonctionnalités (au niveau de la classe-interface) en limitant les risques d'oublis (la compilation n'étant pas possible sans l'implémentation complète au niveau des formulaires).

    Je trouve que c'est lourd à mettre en place pour de petits projets.
    Cela pourrait quand même se justifier si on développe du code réutilisable dans de nombreux projets.

    En revanche dans des projets "larges" la question de la lourdeur est vite relativisée et cette méthode de travail procure des gains notables.
    _

  6. #6
    Membre expert
    Avatar de mout1234
    Profil pro
    Inscrit en
    novembre 2006
    Messages
    2 210
    Détails du profil
    Informations personnelles :
    Âge : 50
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : novembre 2006
    Messages : 2 210
    Points : 3 223
    Points
    3 223
    Par défaut
    Salut,

    Je découvre par hasard ce post avec beaucoup d'intérêt.

    JBO, deux questions stp:

    • depuis quand (quelle version Office) existe l'instruction Implements?
    • Peux-tu citer quelques exemples de méthodes de ton interface cFormApp, histoire de mieux situer l'avantage de cette méthode de dev qui me plait bien ?
      Je ne vois pas bien notamment ce qui peut ainsi te permettre de diminuer autant ton nombre de formulaires par le seul apport de cette interface.
    ............................................................................................

    Dans l'intérêt de tous, ne posez pas de questions techniques par messages privés.

  7. #7
    Membre émérite

    Profil pro
    Inscrit en
    février 2005
    Messages
    1 749
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : février 2005
    Messages : 1 749
    Points : 2 312
    Points
    2 312
    Par défaut
    Bonjour,
    Citation Envoyé par mout1234 Voir le message
    Je découvre par hasard ce post avec beaucoup d'intérêt.
    Je crois aussi que c'est une fonctionnalité digne d'intérêt mais elle implique de se "casser la tête" au moment de la conception (ou re-conception) d'une application.

    Citation Envoyé par mout1234 Voir le message
    JBO, deux questions stp:

    • depuis quand (quelle version Office) existe l'instruction Implements?
    L'instruction Implements est opérationnelle dans Office depuis la version 2000.

    Citation Envoyé par mout1234 Voir le message
    • Peux-tu citer quelques exemples de méthodes de ton interface cFormApp, histoire de mieux situer l'avantage de cette méthode de dev qui me plait bien ?
      Je ne vois pas bien notamment ce qui peut ainsi te permettre de diminuer autant ton nombre de formulaires par le seul apport de cette interface.
    Pour ce qui est de la réduction miraculeuse du nombre de formulaires, j'ai fait un raccourci dans mon explication.
    En fait, en mentionnant cet effet bénéfique, je voulais juste témoigner de l'effet-levier qu'on est en droit d'attendre d'une conception qui s'appuie sur le principe d'implémentation d'interface.

    Maintenant, je peux donner quelques explications et éclaircissements pour montrer qu'il ne s'agit pas juste de "paroles en l'air".

    En fait, il s'agissait d'une application MDI développée avec Access 2000 et qui permettait de suivre de nombreux dossiers avec de nombreuses étapes, elles-mêmes découpées en sous-étapes.
    Pour chaque sous-étape, on mettait en œuvre des fonctionnalités (commandes -> code VBA) propres à la sous-étape.

    Etape 1. Un formulaire par sous-étape
    Initialement, il y avait autant de formulaires que de sous-étapes, mais l'application devenait instable à cause de leur grand nombre.
    En outre, la modification d'une étape (exemple ajout de nouvelles informations) pouvait impliquer la modification de plusieurs formulaires sous-étape.

    Etape 2. Un formulaire par étape permettant de gérer toutes les sous-étapes
    Ensuite, nous avons essayé de gérer toutes les sous-étapes d'une étape dans un seul formulaire (instancié avec l'instruction New), mais le volume de code et le nombre de données à afficher rendait problématique les modifications du formulaire (plantage de l'IDE, sauvegarde d'une durée interminable, code corrompu...).

    N.B. La remarque qui suit ne vaut que pour Access:
    En fait, nous avons constaté qu'il fallait absolument éviter d'avoir beaucoup de code dans le module de code d'un formulaire.

    Etape 3. Restructurer l'application, implémentation d'interfaces
    Donc, le problème était de (1) limiter le nombre de formulaires, (2) sortir le code des commandes d'un formulaire pour le placer dans un module de code indépendant.

    Pour atteindre cet objectif, nous avons (1) simplifié chaque formulaire d'étape avec implémentation d'une interface, (2) déplacé le code de gestion des sous-étapes dans des modules de code de classe distincts qui eux-mêmes implémentent une interface (le contexte informationnel et fonctionnel).
    Selon la complexité des étapes/sous-étapes, toutes les étapes pouvaient être soit regroupées en un seul module de classe, soit détaillées en autant de modules de classe.

    C'est ainsi que le nombre de formulaire a été divisé par 4 et que le volume et la complexité du code ont été répartis dans des classes implémentant les fonctionnalités.
    Il s'agit donc d'une architecture logicielle applicative complexe, à 2 niveaux d'interface... Maintenant, on comprend mieux pourquoi j'ai fait un raccourci dans mon explication précédente.

    Je donnerai des exemples concrets dans un prochain post.
    _

  8. #8
    Membre expert
    Avatar de mout1234
    Profil pro
    Inscrit en
    novembre 2006
    Messages
    2 210
    Détails du profil
    Informations personnelles :
    Âge : 50
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : novembre 2006
    Messages : 2 210
    Points : 3 223
    Points
    3 223
    Par défaut
    Bonjour,

    Merci JBO pour ces explications très détaillées.

    Je devine que cette approche vaut surtout pour de gros développements, ou tout au moins des projets pour lesquels un temps important est consacré à la conception de l'application.

    Pour ma part, je suis plus souvent dans des contextes de projets où il faut développer pour hier des fonctionnalités dont on a à peine pris le temps d'en définir les specs...

    Mais je suis convaincu par tes commentaires que cela doit valoir le coup, même pour des petites applis, en terme d'évolutivité et de lisibilité du code.... reste à me trouver le temps pour expérimenter cela...


    Merci encore et bon Implementations
    ............................................................................................

    Dans l'intérêt de tous, ne posez pas de questions techniques par messages privés.

  9. #9
    Membre régulier
    Profil pro
    Inscrit en
    avril 2008
    Messages
    150
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : avril 2008
    Messages : 150
    Points : 100
    Points
    100
    Par défaut
    Bonjour,

    Merci JBO pour tous ces éclaircissements.
    En tant que développeur Excel, j'utilise très peu de forms lors de mes dev.
    Mais par contre je vois aisément l'extension du concept au module de classe.
    Ce m'évitera de les reprendre tous si j'ai un nouvel objet à rajouter.
    Donc beaucoup moins de maintenance!!!!

    J'appliquerais tes conseils pour mes futurs dev.

    JBO

  10. #10
    Membre émérite

    Profil pro
    Inscrit en
    février 2005
    Messages
    1 749
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : février 2005
    Messages : 1 749
    Points : 2 312
    Points
    2 312
    Par défaut Exemple d'interface
    Comme promis, voici un exemple "assez simple" d'implémentation d'interface.
    L'exemple est appliqué à Access, mais ce serait aussi "facile" avec Excel, ou autres...

    Dans cet exemple, l'objectif est d'ajouter dans la barre de menu d'Access un nouveau menu dont la liste d'options est dynamiquement adaptée en fonction de l'objet actif (l'objet fenêtré qui détient le focus).

    * La légende (Caption) du nouveau menu est: "Spécial implémentation".

    * Ce menu peut travailler avec différents types d'objets: Form, Report et Datasheet (Table ou Query).

    La vue synthétique ci-dessous illustre la faculté de ce menu à s'adapter à l'objet actif en affichant une liste spécifique d'options de menu.



    Avec une interface, il est possible de spécifier les modalités d'une coopération entre le menu et l'objet actif.
    On va simplement énoncer toutes les fonctionnalités à implémenter pour les classes d'objet qui déclareront s'y conformer.

    Évidemment, la conception d'une interface n'est pas quelque chose de trivial, ni d'instantané.

    * Il faut d'abord réfléchir aux interactions entre menu et objets:
    ____ menu <=> objet de type Form
    ____ menu <=> objet de type Report
    ____ menu <=> objet de type Datasheet

    * Avec chacune de ces situations spécifiques, menu et objets sont trop fortement couplés; leur réutilisation est difficile; la prise en compte d'un nouveau type d'objet demande toujours autant d'effort, voire même plus d'effort.
    Ici le menu "connait" la manière de travailler qui convient selon qu'il s'agit d'un Form, d'un Report, d'un Datasheet... Conséquence: taille volumineuse du code; complexité du code.

    * Grâce à l'interface, il est relativement aisé d'insérer une couche d'abstraction qui procure le découplage souhaité entre menu et objets:
    ____ menu <= interface
    ____________ interface => objet de type Form
    ____________ interface => objet de type Report
    ____________ interface => objet de type Datasheet
    Le menu utilise l'interface: il sait comment travailler avec tout objet conforme à l'interface.
    Une classe d'objet implémente l'interface: la conception de la classe de l'objet est simplifiée car le "périmètre" est connu.

    Pour revenir à l'exemple, cette interface est définie au moyen d'un module de classe que j'ai appelé iMenuBarOptions.
    Avec ce nom, j'ai voulu donner un sens précis à l'interface l'interface est focalisée sur les options à afficher dans le menu et l'exécution des traitements correspondant.

    Par convention, dans le monde Windows les interfaces sont facilement identifiées par la première lettre de leur nom qui est toujours la lettre I... par similitude avec la première lettre du mot "Interface".

    En lisant l'interface iMenuBarOptions on apprend qu'une classe d'objet conforme doit pouvoir:
    * fournir un identificateur permettant d'associer étroitement l'objet actif et une liste d'options,
    * fournir la liste des options à afficher par le menu (ou modifier directement le menu),
    * fournir une référence (type Object du VBA) sur l'objet réel (objet actif), instance d'un Form Report, Datasheet...
    * à partir d'un clic souris sur une option affichée dans le menu, lancer l'exécution du code correspondant, implémenté dans l'objet actif.

    Module de classe iMenuBarOptions
    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
    Option Explicit
     
    ' Pour empêcher d'utiliser un objet qui instancie directement l'interface,
    ' toutes les procédures/propriétés de l'interface déclenche une erreur récupérable standard.
    '   Erreur 445: L'objet ne gère pas cette action
     
    Public Property Get OptionsId() As String
        ' interface à implémenter
        Err.Raise 445, "iMenuBarOptions"
    End Property
     
    Public Function OptionsLister(oMenu As Office.CommandBarPopup, ByRef tabOptions_out() As String) As Boolean
        ' interface à implémenter
        Err.Raise 445, "iMenuBarOptions"
    End Function
     
    Public Property Get Object() As Object
        ' interface à implémenter
        Err.Raise 445, "iMenuBarOptions"
    End Property
     
    Public Sub OptionClick(oCtrl As Office.CommandBarControl, nIndex As Integer)
        ' interface à implémenter
        Err.Raise 445, "iMenuBarOptions"
    End Sub
    Je m'arrête là pour aujourd'hui, mais je pense développer les points suivants:
    (1) Comment le menu utilise-t-il l'interface iMenuBarOptions ?
    (2) Comment l'objet actif est-il référencé ?
    (3) Exemple d'implémentation de l'interface iMenuBarOptions (Form ou Report ou Datasheet ???)

    En attendant, je vous donne l'exemple complet en pièce jointe.
    C'est de l'Access 2000, les versions antérieures d'Access ne permettent pas l'implémentation d'interface.

    [EDIT] Merci à Maxence d'avoir signalé un bug... J'ai changé la pièce jointe. [/EDIT]
    _
    Fichiers attachés Fichiers attachés

  11. #11
    Membre expert
    Avatar de mout1234
    Profil pro
    Inscrit en
    novembre 2006
    Messages
    2 210
    Détails du profil
    Informations personnelles :
    Âge : 50
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : novembre 2006
    Messages : 2 210
    Points : 3 223
    Points
    3 223
    Par défaut
    Bonsoir,

    Je viens de regarder d'un peu plus prés ton exemple très intéressant.

    Au delà de l'intérêt concret qu'il peut représenter, il présente comment on peut tirer partie de la notion d'interface.

    On y voit notamment les procédures Menu_OnAction et et Option_OnAction qui utilisent un objet déclaré selon la classe implémentée et ainsi gérer aussi bien un formulaire qu'un état.

    Je peine toutefois à imaginer que l'usage d'interface ait apporté à lui seul une diminution substantielle du code par rapport à de simples menus spécifiques à chaque type d'objet. J'ai plus la conviction que c'est ton architecture dans son ensemble, tirant entre autres partie des implémentations qui en est la source.


    Merci encore
    ............................................................................................

    Dans l'intérêt de tous, ne posez pas de questions techniques par messages privés.

  12. #12
    Membre émérite

    Profil pro
    Inscrit en
    février 2005
    Messages
    1 749
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : février 2005
    Messages : 1 749
    Points : 2 312
    Points
    2 312
    Par défaut
    Citation Envoyé par mout1234 Voir le message
    Je peine toutefois à imaginer que l'usage d'interface ait apporté à lui seul une diminution substantielle du code par rapport à de simples menus spécifiques à chaque type d'objet.
    L'usage d'interface permet-il de réduire le volume de code ?

    Oui et Non. Je m'explique:

    Non, dans l'absolu je ne pense pas que le volume de code "vraiment utile" s'en trouve réduit.

    Oui, parce qu'il favorise la factorisation de codes redondants et dupliqués.
    Mais la réduction du volume du code est plus le résultat d'une "bonne" conception ou re-conception, dont l'interface ne serait qu'une des modalités.

    Citation Envoyé par mout1234 Voir le message
    J'ai plus la conviction que c'est ton architecture dans son ensemble, tirant entre autres partie des implémentations qui en est la source.
    Avec l'utilisation d'une interface, on est obligé de repenser et rationnaliser "la logique" des composantes d'une application.

    Dans l'exemple du menu "Spécial implémentation" on va distinguer 3 "logiques":

    (1) La logique de gestion des options d'un menu qui est concrétisée par les procédures Menu_OnAction() et Option_OnAction().
    Cette logique est unique car étroitement liée à une interface, ici iMenuBarOptions.
    Il n'est pas nécessaire de "comprendre l'environnement" et donc pas nécessaire d'avoir autant de "logiques" que d'objets actifs (Form, Report, Query, Table).

    (2) La logique d'accès à l'objet actif, concrétisée par la procédure MenuBarOptions().
    Cette logique exploite le contexte courant connu d'elle seule (ici l'environnement est perçu à travers l'objet Screen et la propriété CurrentObjectType).
    En retour, elle désigne un objet conforme à l'interface iMenuBarOptions, donc directement utilisable par la logique de gestion des options d'un menu.
    Cela peut faire penser au "pattern factory" qui sait fournir un objet opérationnel et du bon type (ou instance de la bonne classe) à une "logique commune" basée sur une interface (ou une classe de base).

    (3) La logique d'exécution des commandes liées aux options du menu.
    Ces commandes sont concrétisées par autant de procédures, codées directement dans le module de code de l'objet actif.

    _____---====OOOOO====---

    Je profite de l'occasion pour donner le code de la procédure MenuBarOptions() qui implémente la logique d'accès à l'objet actif (cf. le point 2).
    C'est cette logique qui devrait être modifiée si on souhaite adapter le menu "Spécial implémentation" à de nouveaux types d'objets.

    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
    Public Function MenuBarOptions() As iMenuBarOptions
        Static oActiveObject As Object
        Dim oForm As Access.Form
     
    On Error GoTo ProcErr
     
        Select Case Application.CurrentObjectType
        Case acTable, acQuery
            ' Une erreur est déclenchée si ActiveDatasheet inaccessible
            Set oForm = Screen.ActiveDatasheet
     
            ' Table et Query n'ont pas de module de code
            ' ==> créer dynamiquement un objet qui implémente l'interface
            Set oActiveObject = New cDataSheet
     
        Case acForm
            ' Trouver l'objet Form actif
            Set oActiveObject = Screen.ActiveForm
     
        Case acReport
            ' Trouver l'objet Report actif
            Set oActiveObject = Screen.ActiveReport
     
        Case Else
            ' Pas d'objet actif "exploitable"
            Set oActiveObject = Nothing
     
        End Select
     
        ' Accéder à l'interface iMenuBarOptions de l'objet actif
        ' Une erreur est déclenchée si l'objet actif n'implémente pas l'interface
        Set MenuBarOptions = oActiveObject
     
        Exit Function
     
    ProcErr:
        Set MenuBarOptions = Nothing
     
    End Function
    Si je veux mettre en œuvre dans Excel le menu "Spécial implémentation", je conserve la logique (1) et j'adapte la logique (2).
    _

  13. #13
    Membre à l'essai
    Profil pro
    Inscrit en
    avril 2008
    Messages
    20
    Détails du profil
    Informations personnelles :
    Âge : 33
    Localisation : Royaume-Uni

    Informations forums :
    Inscription : avril 2008
    Messages : 20
    Points : 24
    Points
    24
    Par défaut
    Hello,

    Je decouvre ce topic interessant et quelques chose m'interpelle dans ton premier post:
    (2) d'obtenir un code plus robuste parce que les appels de méthodes sont vérifiés à la compilation (liaison dynamique "late binding" mais avec la rigueur du contrôle de type).
    Qu'est ce que tu entends par les appels verifies a la compilation et le controle de type ? Je pensais que justement avec le polymorphisme et les liaisons dynamiques, c'etait traite a l'execution ?

    Merci d'avance

  14. #14
    Membre expert
    Avatar de mout1234
    Profil pro
    Inscrit en
    novembre 2006
    Messages
    2 210
    Détails du profil
    Informations personnelles :
    Âge : 50
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : novembre 2006
    Messages : 2 210
    Points : 3 223
    Points
    3 223
    Par défaut
    Citation Envoyé par Pierre.M Voir le message
    Hello,

    Je decouvre ce topic interessant et quelques chose m'interpelle dans ton premier post:


    Qu'est ce que tu entends par les appels verifies a la compilation et le controle de type ? Je pensais que justement avec le polymorphisme et les liaisons dynamiques, c'etait traite a l'execution ?

    Merci d'avance
    Hello Pierre,

    La clause Implements oblige, dés la compilation, à implémenter effectivement toutes les méthodes de l'interface. Quant au code référençant l'objet, la compilation est en mesure de vérifier la conformité à la classe d'interface.
    Donc, tout est contrôlé à la compil et non à l'exécution... je me trompe JBO ?
    ............................................................................................

    Dans l'intérêt de tous, ne posez pas de questions techniques par messages privés.

  15. #15
    Membre émérite

    Profil pro
    Inscrit en
    février 2005
    Messages
    1 749
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : février 2005
    Messages : 1 749
    Points : 2 312
    Points
    2 312
    Par défaut
    Salut mout1234:

    Je suis totalement d'accord avec tes propos.
    Tu as exprimé synthétiquement le rôle dévolu à l'interface.

    Explication à Pierre.M, que je salue au passage:

    Quand j'évoque la "non robustesse" des codes VB/VBA, je pense à des développements où le développeur préfère utiliser des objets de type Object (donc ne rien typer du tout) parce que sinon il a des erreurs de compilation.
    Bien que totalement déconseillée et à proscrire, cette pratique perdure puisqu'elle est possible.

    Encore pire avec VBA: peut être que le développeur ne sait pas lancer la compilation (cf. ma signature ) !?

    Bien sûr qu'un tel code "non typé" (ou non compilé) peut fonctionner, mais le développeur travaille alors les "yeux bandés" et "sans filet". Au moindre faux pas...

    Une remarque en passant: l'absence de typage, c'est exactement la situation du VBScript non !?

    Il faut aussi comprendre que "liaison dynamique" ne s'oppose pas à "typage des objets".
    Simplement, ici le type qui est utilisé est un "type de base", spécifié au moyen d'une classe-interface dans notre cas.
    Ce "type de base" ne désigne pas "à l'avance" la procédure qui sera exécutée... la liaison sera donc dynamique.
    _

  16. #16
    Membre à l'essai
    Profil pro
    Inscrit en
    avril 2008
    Messages
    20
    Détails du profil
    Informations personnelles :
    Âge : 33
    Localisation : Royaume-Uni

    Informations forums :
    Inscription : avril 2008
    Messages : 20
    Points : 24
    Points
    24
    Par défaut
    Il faut aussi comprendre que "liaison dynamique" ne s'oppose pas à "typage des objets".
    C'etait la dessus que je m'embrouillais
    Merci a vous 2 pour les precisions, c'est plus clair!

    Une remarque en passant: l'absence de typage, c'est exactement la situation du VBScript non !?
    Pour VBS il y a egalement le type implicite Variant ainsi que les types de base Double, Long, String etc. On peut ecrire des classes et creer des objets, par contre l'heritage et le polymorphisme ne sont pas geres.

  17. #17
    Membre expert
    Avatar de mout1234
    Profil pro
    Inscrit en
    novembre 2006
    Messages
    2 210
    Détails du profil
    Informations personnelles :
    Âge : 50
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : novembre 2006
    Messages : 2 210
    Points : 3 223
    Points
    3 223
    Par défaut
    Citation Envoyé par Pierre.M Voir le message
    C'etait la dessus que je m'embrouillais
    Merci a vous 2 pour les precisions, c'est plus clair!


    Pour VBS il y a egalement le type implicite Variant ainsi que les types de base Double, Long, String etc. On peut ecrire des classes et creer des objets, par contre l'heritage et le polymorphisme ne sont pas geres.
    Je ne voudrais pas que l'on change de sujet... mais le VBS ne connait que le type Variant il me semble ...
    ............................................................................................

    Dans l'intérêt de tous, ne posez pas de questions techniques par messages privés.

  18. #18
    Membre à l'essai
    Profil pro
    Inscrit en
    avril 2008
    Messages
    20
    Détails du profil
    Informations personnelles :
    Âge : 33
    Localisation : Royaume-Uni

    Informations forums :
    Inscription : avril 2008
    Messages : 20
    Points : 24
    Points
    24
    Par défaut
    mais le VBS ne connait que le type Variant il me semble
    Oui. En fait les "autres types" sont des sous-types de Variant, autant pour moi je me suis mal exprime

    Voila pour la paranthese VBS!

  19. #19
    Membre confirmé Avatar de Tonioyo
    Homme Profil pro
    Développeur informatique
    Inscrit en
    juin 2008
    Messages
    343
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : juin 2008
    Messages : 343
    Points : 517
    Points
    517
    Par défaut
    Bonjour,

    Ce débat est très intéressant en effet mais les applications à ce concept dépasse largement l'utilisation des interfaces graphiques.
    Pour ma part, il est bien question de polymorphisme à une exception près, c'est cela qui fait que ce n'est pas du vrai polymorphisme de mon point de vue.

    Une classe mamifère contient des propriétés et méthodes définissant un mamifère.
    Une classe Lapin contient les propriétés et méthodes pour un lapin
    Une classe Raton-Laveur contient les propriétés et méthodes d'un raton laveur.

    Avec Implements Un Lapin est un mamifère et un Raton-Laveur l'est aussi, jusque là ok.

    mais lorsque l'on dis : J'ai un mamifère (implémentation / New), c'est un lapin (Affectation de notre mamifère comme lapin). Si je veux accèder aux propriétés et méthodes de mon mamifère en VBA (tout du moins Access VBA), on a accès qu'aux propriétés et méthodes de notre mamifère ce qui est juste et faux à la fois car à partir de mamifère on devrait avoir accès à la partie mamifère et à la partie Lapin. (Tout du moins de mémoire cela fonctionne comme ça en C++)

    Pour synthétiser lorsque l'on s'adresse à un mamifère quelque soit sont type plus précis on accède qu'à l'implémentation Mamifère de notre Objet (d'où le nom du mot clé Implément).

    De manière générale, on peu considérer ça comme du polymorphisme.

    C'est important car l'impact sur les moyennes - grosses applis permet un gros gains d'organisation et de clareté dans un code bien écrit
    loi de LeBlanc : Plus tard signifie jamais. extrait de Coder proprement Auteur:Robert C. Martin

  20. #20
    Responsable
    Office & Excel

    Avatar de Pierre Fauconnier
    Homme Profil pro
    Formateur et développeur informatique indépendant
    Inscrit en
    novembre 2003
    Messages
    14 543
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : Formateur et développeur informatique indépendant
    Secteur : Enseignement

    Informations forums :
    Inscription : novembre 2003
    Messages : 14 543
    Points : 40 101
    Points
    40 101
    Billets dans le blog
    58
    Par défaut
    En ce qui me concerne, j'ai trouvé avec l'implémentation de quoi faciliter la gestion des formulaires en Access, grâce aux procédures génériques implémentées...
    "Plus les hommes seront éclairés, plus ils seront libres" (Voltaire)
    ---------------
    Mes remarques et critiques sont purement techniques. Ne les prenez jamais pour des attaques personnelles...
    Une fois pour toutes, je donne mon avis. Je ne vais pas le répéter à chaque message...
    Si je propose une solution générique sur votre solution spécifique, c'est parce que, fainéant de nature, je privilégie le réutilisable...
    Le VBA ne palliera jamais une mauvaise conception de classeur ou un manque de connaissances des outils natifs d'Excel...
    Vous souhaitez rédiger pour DVP? Contactez-moi
    VBA pour Excel? Pensez D'ABORD en EXCEL avant de penser en VBA...
    ---------------

Discussions similaires

  1. Réponses: 12
    Dernier message: 01/07/2004, 12h03
  2. Réponses: 8
    Dernier message: 04/06/2004, 10h13
  3. Moteur physique : comment l'implémenter ?
    Par haypo dans le forum Algorithmes et structures de données
    Réponses: 15
    Dernier message: 17/12/2003, 13h56
  4. Réponses: 2
    Dernier message: 06/07/2002, 13h36
  5. Implémentation des fonctions mathématiques
    Par mat.M dans le forum Mathématiques
    Réponses: 9
    Dernier message: 17/06/2002, 17h19

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