Forum des développeurs  

Le forum de référence en programmation et développement. Articles, cours et tutoriels du débutant au chef de projet et DBA confirmé.
Précédent   Forum des développeurs > Hardware, Systèmes et Logiciels > Microsoft Office > Général VBA

Général VBA Forum général VBA . Pour les logiciels spécifiques (Access, Excel, Word, ...), postez dans les bons sous forums.

Réponse
 
Outils de la discussion
Vieux 30/10/2008, 20h41   #1 (permalink)
Membre émérite
 
Avatar de =JBO=
 
Date d'inscription: février 2005
Localisation: France - Drôme
Messages: 951
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 :
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 :
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 :
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 :
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 :
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.
_
__________________
Les bons réflexes VB/VBA: __ Option Explicit ___ Toujours compiler le code avant de tester ! (dans l'EDI, menu Débogage, commande Compiler)

Dernière modification par =JBO= ; 10/11/2008 à 12h44 Motif: Ajout d'un commentaire plus explicatif + Correction
=JBO= est déconnecté   Envoyer un message privé Réponse avec citation
Vieux 30/10/2008, 20h54   #2 (permalink)
Rédacteur/Modérateur
 
Avatar de Pierre Fauconnier
 
Date d'inscription: novembre 2003
Localisation: Theux (Belgique)
Âge: 42
Messages: 3 299
Envoyer un message via Skype™ à Pierre Fauconnier
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 :
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...
__________________
Pierre Fauconnier
--------------------
"Plus les hommes seront éclairés, plus ils seront libres" (Voltaire)
Pensez au tag

Mon blog sur DVP - Mes petits papiers sur DVP - Nouveau: Groupe des formateurs - Nouveau: Groupes développeurs QSEA
Je ne peux en aucun cas être tenu pour responsable des conséquences de l'utilisation des codes que je fournis dans le cadre des réponses apportées sur les forums, même s'il s'avérait que ces codes sont erronés ou amènent à des dysfonctionnements, de manière manifeste ou non.
Pierre Fauconnier est déconnecté   Envoyer un message privé Réponse avec citation
Vieux 31/10/2008, 12h49   #3 (permalink)
Membre émérite
 
Avatar de =JBO=
 
Date d'inscription: février 2005
Localisation: France - Drôme
Messages: 951
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.
_
__________________
Les bons réflexes VB/VBA: __ Option Explicit ___ Toujours compiler le code avant de tester ! (dans l'EDI, menu Débogage, commande Compiler)

Dernière modification par =JBO= ; 31/10/2008 à 13h21 Motif: Un effort pour faire le point sur "les" polymorphismes.
=JBO= est déconnecté   Envoyer un message privé Réponse avec citation
Vieux 31/10/2008, 14h32   #4 (permalink)
Rédacteur/Modérateur
 
Avatar de Pierre Fauconnier
 
Date d'inscription: novembre 2003
Localisation: Theux (Belgique)
Âge: 42
Messages: 3 299
Envoyer un message via Skype™ à Pierre Fauconnier
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
__________________
Pierre Fauconnier
--------------------
"Plus les hommes seront éclairés, plus ils seront libres" (Voltaire)
Pensez au tag

Mon blog sur DVP - Mes petits papiers sur DVP - Nouveau: Groupe des formateurs - Nouveau: Groupes développeurs QSEA
Je ne peux en aucun cas être tenu pour responsable des conséquences de l'utilisation des codes que je fournis dans le cadre des réponses apportées sur les forums, même s'il s'avérait que ces codes sont erronés ou amènent à des dysfonctionnements, de manière manifeste ou non.
Pierre Fauconnier est déconnecté   Envoyer un message privé Réponse avec citation
Vieux 31/10/2008, 14h57   #5 (permalink)
Membre émérite
 
Avatar de =JBO=
 
Date d'inscription: février 2005
Localisation: France - Drôme
Messages: 951
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.
_
__________________
Les bons réflexes VB/VBA: __ Option Explicit ___ Toujours compiler le code avant de tester ! (dans l'EDI, menu Débogage, commande Compiler)
=JBO= est déconnecté   Envoyer un message privé Réponse avec citation
Vieux 03/11/2008, 00h21   #6 (permalink)
Modérateur
 
Avatar de mout1234
 
Date d'inscription: novembre 2006
Localisation: Paris
Âge: 39
Messages: 1 759
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.


Les FAQs les tutos Les Sources Access Profitez de ces mines d'or...

Postez dans le bon sous forum et mentionnez la version
mout1234 est déconnecté   Envoyer un message privé Réponse avec citation
Vieux 03/11/2008, 15h39   #7 (permalink)
Membre émérite
 
Avatar de =JBO=
 
Date d'inscription: février 2005
Localisation: France - Drôme
Messages: 951
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.
_
__________________
Les bons réflexes VB/VBA: __ Option Explicit ___ Toujours compiler le code avant de tester ! (dans l'EDI, menu Débogage, commande Compiler)

Dernière modification par =JBO= ; 12/11/2008 à 21h11
=JBO= est déconnecté   Envoyer un message privé Réponse avec citation
Vieux 04/11/2008, 14h13   #8 (permalink)
Modérateur
 
Avatar de mout1234
 
Date d'inscription: novembre 2006
Localisation: Paris
Âge: 39
Messages: 1 759
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.


Les FAQs les tutos Les Sources Access Profitez de ces mines d'or...

Postez dans le bon sous forum et mentionnez la version
mout1234 est déconnecté   Envoyer un message privé Réponse avec citation
Vieux 06/11/2008, 13h14   #9 (permalink)
Candidat au titre de Membre du Club
 
Date d'inscription: avril 2008
Messages: 23
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
-={-_-}=- est déconnecté   Envoyer un message privé Réponse avec citation
Vieux 06/11/2008, 23h50   #10 (permalink)
Membre émérite
 
Avatar de =JBO=
 
Date d'inscription: février 2005
Localisation: France - Drôme
Messages: 951
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 :
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
Type de fichier : zip MenuBarOptions.zip (33,2 Ko, 34 affichages)
__________________
Les bons réflexes VB/VBA: __ Option Explicit ___ Toujours compiler le code avant de tester ! (dans l'EDI, menu Débogage, commande Compiler)

Dernière modification par =JBO= ; 11/11/2008 à 11h36 Motif: Correction bug dans pièce jointe + Reprise des paragraphes obscurs
=JBO= est déconnecté   Envoyer un message privé Réponse avec citation
Vieux 11/11/2008, 23h54   #11 (permalink)
Modérateur
 
Avatar de mout1234
 
Date d'inscription: novembre 2006
Localisation: Paris
Âge: 39
Messages: 1 759
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.


Les FAQs les tutos Les Sources Access Profitez de ces mines d'or...

Postez dans le bon sous forum et mentionnez la version
mout1234 est déconnecté   Envoyer un message privé Réponse avec citation
Vieux 12/11/2008, 14h19   #12 (permalink)
Membre émérite
 
Avatar de =JBO=
 
Date d'inscription: février 2005
Localisation: France - Drôme
Messages: 951
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 :
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).
_
__________________
Les bons réflexes VB/VBA: __ Option Explicit ___ Toujours compiler le code avant de tester ! (dans l'EDI, menu Débogage, commande Compiler)

Dernière modification par =JBO= ; 12/11/2008 à 21h10 Motif: Commentaires de la procédure MenuBarOptions() revus++
=JBO= est déconnecté   Envoyer un message privé Réponse avec citation
Vieux 12/11/2008, 16h41   #13 (permalink)
Invité régulier
 
Date d'inscription: avril 2008
Localisation: Londres
Âge: 22
Messages: 19
Par défaut

Hello,

Je decouvre ce topic interessant et quelques chose m'interpelle dans ton premier post:
Citation:
(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
Pierre.M est déconnecté   Envoyer un message privé Réponse avec citation
Vieux 12/11/2008, 18h44   #