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

Macros et VBA Excel Discussion :

Public or not Public ?


Sujet :

Macros et VBA Excel

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éclairé
    Homme Profil pro
    Inscrit en
    Janvier 2013
    Messages
    716
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Janvier 2013
    Messages : 716
    Par défaut Public or not Public ?
    Bonjour,

    Ces derniers temps, je m'interroge sur le passage des variables en arguments (mieux vaut tard que jamais).

    A défaut de maîtriser le sujet, j'avais, dans mon dernier classeur, provisoirement fait un usage, a priori abusif, de la déclaration de mes variables en Public dans un module standard dédié. Avantage (pour moi) de les regrouper au même endroit.

    Je viens de tomber sur ce fil :
    https://www.developpez.net/forums/d2...tion-variable/

    Patrice740 y écrit :
    Il faut utiliser les variables publiques avec parcimonie : uniquement quand c'est indispensable, c'est à dire quasiment jamais !
    Pierre Fauconnier surenchérit :
    (...) On voit bien qu'il n'y a aucune variable publique (Patrice740), celles-ci n'ayant rien à faire dans du code que je qualifie de professionnel, à de très rares exceptions près.
    Je ne peux que m'incliner devant les "bonnes pratiques" de l'un et l'autre.

    Néanmoins, je note que la question d'eriiic reste sans réponse et cela m'intrigue :
    Je ne comprends pas bien ce rejet des variables publiques et cette volonté de vouloir s'en passer à tous crins.
    J'ai bien compris qu'il est préférable de passer par les Arguments mais quel est l'inconvénient des variables Public (bien pratiques par ailleurs) ?

    En vous remerciant d'avance pour vos lumières,

    Cordialement,
    jp

    PS : Même avec mes variables Public, mon classeur semble fonctionner "normalement"

  2. #2
    Membre Expert Avatar de Thumb down
    Homme Profil pro
    Retraité
    Inscrit en
    Juin 2019
    Messages
    1 592
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Juin 2019
    Messages : 1 592
    Par défaut
    Bonsoir,
    Ce n'est pas une hérésie d'utiliser des variables public dans un module standard dédié, elles sont utilisables dans n'importe quelle propriété ou méthode c'est bien pratique.

    Le problème n'est pas là ; le problème est qu'on ne les voit pas et qu'on les oublie. Quand j'ai besoin d'une variable je la déclare , je l'initialise etc.

    Le passage de variables en paramètres permet de savoir qui fait quoi et avec quoi c'est juste plus lisible et sa évite le mélange de genres !

    Je suis une procédure et je fais ça sans apport d'information Venu de je ne sais où et comment !

  3. #3
    Membre Expert
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    1 540
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Juillet 2006
    Messages : 1 540
    Par défaut
    Les variables public (ou globales) ont des défauts majeur qui supplantent tous leur avantages:
    - violent la Loi de Demeter (https://en.wikipedia.org/wiki/Law_of_Demeter).
    - Elles introduisent de fortes dépendances.
    - Elles sont accessibles en écriture par n'importe qui, n'importe quand, plus grave: sans aucun contrôle.
    Tous cela est source de bugs sournois, particulièrement difficile (voir impossible) à corriger.
    - La seul protection contre tous ces désagréments est la discipline du programmeur, chose extrêmement rare.

    La plupart des développeurs les utilisent à foison, parce que c'est enseigné particulièrement tôt dans les cours (d'ailleurs existe t'il un bon cours de VBA sur le net ?), par paresse, par manque d'éducation aux bonnes pratiques (ce genre de chose sont trop souvent survolées en annexe, à la fin des cours, le truc qu'on ignore royalement vu que c'est optionnel).

    Donc, fait toi une faveur, bannis les globales de tes développements, tu ne t'en porteras que mieux.

  4. #4
    Membre éclairé
    Homme Profil pro
    Inscrit en
    Janvier 2013
    Messages
    716
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Janvier 2013
    Messages : 716
    Par défaut
    Bonjour,

    Merci pour ces explications.
    Je retiens que ça peut être pratique mais pas académique. Je comprends que c'est plus "propre" et plus lisible d'utiliser des arguments et j'ai donc essayé d'adopter cette "bonne pratique".

    Sans surprise, à la première variable Public que j'ai voulu exfiltrée, ça a buggé ! Je pense que je n'ai pas bien compris certaines subtilités (voire toutes).

    Ex :
    Avant :
    Public Titre As String dans un module standard dédié
    Après :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    Option Explicit
    Private Sub Workbook_Open()
    Dim Titre As String
     
        Mon_Classeur = ActiveWorkbook.Name
        Titre = ThisWorkbook.BuiltinDocumentProperties("title").Value
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    Private Sub UserForm_Initialize(Titre As String)
     
        TextBox1.Value = "vers° " & Titre
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    Sub Indexation_Svg(Titre As String)
     
    (...)
     
        FichierIndexé = Format(Now, "yyyy.mm.dd hh""h""nn") & " - " & Plage_Onglets_Svg & " - " & "(" & Titre & ") - " & ThisWorkbook.Name
    Conclusion : 1er essai = fiasco (sans parler de la non-maîtrise à ce stade des ByVal, ByRef bien qu'ayant lu quelques explications à ce sujet)

    Questions :

    • Si une variable est appelée par plusieurs Sub, il faut les répéter chaque fois ?
    • Les

    "Private" Sub ne sont-elles pas un obstacle ? C'est d'ailleurs pour cette raison que j'avais recouru aux variables Public.

    Entre la Loi de Demeter et l'adage "le mieux est l'ennemi du bien", mon coeur balance.

    Cordialement,

  5. #5
    Membre Expert
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    1 540
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Juillet 2006
    Messages : 1 540
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Private Sub UserForm_Initialize(Titre As String)
    Les gestionnaires d'évènement ont une signature particulière attendue par le système, et tu ne dois pas les changer.

    Si tu veux faire passer des variables à un formulaire, il va te falloir trouver une autre mécanique.
    - Ecrire des propriétés.
    - Ecrire une méthode qui recevrai la (ou les) variables en argument.
    - Ecrire un pseudo constructeur.
    - Exploiter les évènements.
    - Mettre en œuvre le design Pattern Observer.

    Quand aux mot clefs ByVal / ByRef (que tu devrais toujours employer), c'est simple:
    Un argument déclaré ByVal reçoit une copie de la variable passée en paramètre. Les changements effectués sur l'argument n'affectent pas le code appelant (pour faire simple: Paramètre d'entrée).
    Un argument passé ByVal reçoit une référence vers la variable passée en paramètre, tout changement effectués sur l'argument sera répercuté sur le code appelant (pour faire simple: Paramètre d'entrée/sortie ou paramètre de sortie).

  6. #6
    Invité
    Invité(e)
    Par défaut
    Bonjour le fil,

    Franchement deedolith tu es sérieux avec ta loi demeter et autre

    @jpma75, pourquoi se casser la tête ?
    J'utilise des variables publiques au quotidien dans mes dev. et je n'ai jamais eu aucun problème

    En revanche, il est clair qu'il ne faut pas la perdre de vue

    Dans un module
    Ensuite
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    Private Sub Workbook_Open() 
    Titre = ThisWorkbook.BuiltinDocumentProperties("title").Value


    Et dans ton USF
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    Private Sub UserForm_Initialize()
     TextBox1.Value = "vers° " & Titre
      Titre = ""  ' Penser à vider la variable puliqur


    Je ne vois franchement pas ou est le souci

    A+


  7. #7
    Membre Expert Avatar de Thumb down
    Homme Profil pro
    Retraité
    Inscrit en
    Juin 2019
    Messages
    1 592
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Juin 2019
    Messages : 1 592
    Par défaut
    Bonjour,
    Ce qui doit être partagé entre fonction est passé en paramètres dans la déclaration de la dite fonction.

    En tous les cas c'est comme ça que je vois les choses !

  8. #8
    Membre éclairé
    Homme Profil pro
    Inscrit en
    Janvier 2013
    Messages
    716
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Janvier 2013
    Messages : 716
    Par défaut
    Bonjour,

    @deedolith

    Les gestionnaires d'évènement ont une signature particulière attendue par le système, et tu ne dois pas les changer.
    Si tu veux faire passer des variables à un formulaire, il va te falloir trouver une autre mécanique.
    La mécanique que tu décris n'est pas de mon niveau et je ne vais pas être plus royaliste que le roi (a fortiori par les temps qui courent et où certains rêvent de leur (re)couper la tête ). Je comprends mieux à présent pourquoi mon premier essai a été un fiasco.
    Merci pour les compléments concernant ByVal et ByRef. Il ne me reste plus qu'à pratiquer !

    @BrunoM45

    Merci !
    Titre = "" ' Penser à vider la variable pulique
    Avant de lire la réponse de binarygirl, j'allais poser la question de savoir pourquoi il fallait vider la variable ?

    Puis-je imaginer que c'est utile (voire nécessaire) dans ce qu'ajoute binarygirl :
    Bref, on déclare en Public ce qui a besoin d'être partagé entre les différentes fonctions du programme. Dans ce cas-ci, ça peut avoir du sens que le Titre soit public puisque c'est une propriété globale de votre application.
    @binarygirl

    Merci !

    Il faut "limiter le scope" autant que possible, et cela d'autant plus si vous allez réutiliser les mêmes noms de variables dans différentes fonctions.
    Scope ? Balayage des modules ??
    Par ailleurs, oui, j'utilise les mêmes noms de variables dans différentes fonctions et j'ai cru que la déclaration en Public allait me poser problème. Chance ou pas, le classeur fonctionne "normalement"
    (je reste curieux de savoir si le "vidage" de la mémoire Public comme le propose BrunoM45 est LA solution).

    on ne laisse pas les noms par défaut comme TextBox1
    Merci pour ce rappel (en général, je renomme...)

    Bref, on déclare en Public ce qui a besoin d'être partagé entre les différentes fonctions du programme. Dans ce cas-ci, ça peut avoir du sens que le Titre soit public puisque c'est une propriété globale de votre application.
    C'est exactement pour cette raison que j'ai (généreusement) déclaré mes variables Public. D'ailleurs, j'avais demandé précédemment :
    Si une variable est appelée par plusieurs Sub, il faut les répéter chaque fois ?
    Et il me semblait, sous réserve de la réponse d'un contributeur, que Public contournait cette difficulté.

    Vous pourriez très bien vous passer d'une variable, et afficher directement la valeur de: ThisWorkbook.BuiltinDocumentProperties("title").Value
    Merci pour cette remarque. Je m'aperçois qu'il y a apparemment une variable superflue.

    Cdt

  9. #9
    Membre Expert Avatar de Thumb down
    Homme Profil pro
    Retraité
    Inscrit en
    Juin 2019
    Messages
    1 592
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Juin 2019
    Messages : 1 592
    Par défaut
    Bonjour,
    Comme je l'ai dit dans mon premier poste, utiliser une variable public n'est pas un crime de l'aise majesté. Tu ne seras pas excommunié de dvp.com si tu y recour.

    Public ar not public tel était la question et ma réponse est invariablement de passer par des paramètres.

    Relaier par des variables public ce qui relève de thisworkbook est une hérésie.

    Pourquoi passer titre en paramètres vu qu'à l'origine li relève de thisworkbook ?

  10. #10
    Membre Expert
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    1 540
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Juillet 2006
    Messages : 1 540
    Par défaut
    Scope, c'est la portée des variables, ou si tu préfère: Leurs visibilité.
    Ce qui définit également leur durée de vie.

    Une variable déclarée dans une fonction n'est visible que dans la fonction elle même.
    Sa durée de vie commence à partir de sa déclaration, et se termine à la fin de la fonction.
    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
    Option Explicit
     
    Sub MySub()
        Dim First As Integer
        First = 10    '// Ok, First est visible dans la fonction.
        Dim myVar As Integer
     
        Second = 25
        Dim Second As Integer    '// Ko, Second est visible dans la fonction mais n'a pas encore été déclarée
    End Sub    '// First est automatiquement détruit
     
    Sub MySecondSub()
        MySub
        First = 10    '// Ko, First n'est visible que dans la fonction MySub
    End Sub
    Il en va de même pour les modules standard, à la différence que les variables déclarées dans un module ont une durée de vie égale à l'application (dans le cas d'excel: De l'ouverture à la fermeture du classeur).
    On peut également définir un indicateur de portée, Public indique que les variables seront visible de partout (variable gloable), Private indique que les variables ne seront visible que dans le module lui même.
    Exemple:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    '// module FirstModule:
    Public First As Integer
    Private Second As Integer
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    '// module SecondModule
    Public Sub MySub()
        First = 10    '// Ok, First est déclaré dans FirstModule en public et a une portée globale (non recommandé)
        MyFirstModule.First = 10    '// Ok, First est déclaré dans FirstModule en public (écriture pour lever les ambiguités).
        Second = 25    '// Ko, Second est declaré Privé dans FirstModule, et n'est pas visible dans SecondModule.
    End Sub
    Idem pour les module de classe, sauf que leur durée de vie commence avec l'instanciation de la classe.
    Exemple:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    '// Module MyClass
    Public First
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    '// Module MyModule:
    Public Sub MySub
        Dim MyInstance As MyClass
        Set MyInstance = New MyClass    '// Instanciation d'un objet de type MyClass
        MyInstance.First = 10    '// Ok, First est public (on préférera cependant passer par des property get / property Let)
        Set MyInstance = Nothing
     
        MyInstance.First = 10    '// Ko, MyInstance a été détruit
        MyClass.First = 10    '// Ko, un objet de type MyClass doit être instancié au préalable
    End Sub
    Normalement, tout cela est expliqué en détail dans les cours ...

  11. #11
    Membre Expert
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    1 540
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Juillet 2006
    Messages : 1 540
    Par défaut
    Une technique que j'emploie souvent avec les classes et les formulaires, dans le but de factoriser mon code (ainsi que d'être conforme au RAII), est d'écrire un "pseudo constructeur" (vu que le seul que VBA fournit est dénué de paramètres), ainsi qu'une fonction "Factory" qui sera en charge de construire l'objet.
    Exemple avec la classe Pair, qui contient une paire de 2 entiers:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    '// Standard Module: Factory
    Public Function Create_Pair(ByVal First As Integer, ByVal Second As Integer)
        Dim Instance As Pair
        Instance = New Pair    '// Instancie un objet de type Pair
        Instance.Create First, Second    '// Appelle le pseudo constructeur
        Set Create_Pair = Instance    '// Retourne l'instance crée
    End Function
    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
    '// Class Module: Pair
    Private mFirst As Integer        '// Variables membre de la classe
    Private mSecond As Integer
     
        '// Pseudo-constructeur: Initialise les variables membre
    Public Sub Create(ByVal First As integer, ByVal Second As Integer)
        mFirst = First
        mSecond = Second
    End Sub
     
        '// Accesseurs:
        '// En lecture seule, car ca n'a pas de sens qu'ils soient en lecture / ecriture
    Public Property Get First() As Integer
        First = mFirst
    End Property
     
    Public Property Get Second() As Integer
        Second = mSecond
    End Property
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    '// Standard Module: TestModule
    Public Sub Test()
        Dim MyPair As Pair
        Set MyPair= Factory.Create_Pair(10, 25)    '// Instancie un objet de type Pair, initialisé avec les valeurs 10 et 25
     
        Debug.Print MyPair.First    '// Affiche 10
        Debug.Print MyPair.Second    '// Affiche 25
    End Sub
    Les formulaires étant dans classes, cette technique est applicable.
    Il faudra cependant veiller à instancier le formulaire, plutot que passer par l'instance globale.

  12. #12
    Membre éclairé
    Homme Profil pro
    Inscrit en
    Janvier 2013
    Messages
    716
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Janvier 2013
    Messages : 716
    Par défaut
    Bonjour,

    Merci à Thumb Down et Deedolith pour les précieuses informations de ces 3 derniers posts (même si le dernier est un peu trop abscons pour moi ainsi que les modules de classes que je n'utilise pas).

    J'ai déjà revu "drastiquement" les variables de mon dernier classeur ;-)

    Cordialement,

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

Discussions similaires

  1. Réponses: 1
    Dernier message: 12/01/2017, 15h52
  2. Erreur "Resource is not public"
    Par Priato dans le forum Android
    Réponses: 6
    Dernier message: 17/04/2012, 23h02
  3. Réponses: 1
    Dernier message: 11/10/2009, 16h24
  4. [Excel] Publication d'une feuille au format .htm
    Par talumn dans le forum Macros et VBA Excel
    Réponses: 3
    Dernier message: 14/02/2009, 03h57
  5. [CR9] publication d'états par RAS
    Par youl dans le forum SAP Crystal Reports
    Réponses: 2
    Dernier message: 10/07/2003, 18h26

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