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 :

Collection de collection


Sujet :

Macros et VBA Excel

  1. #1
    Futur Membre du Club
    Homme Profil pro
    Chargé d'affaire
    Inscrit en
    Janvier 2024
    Messages
    5
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Chargé d'affaire

    Informations forums :
    Inscription : Janvier 2024
    Messages : 5
    Par défaut Collection de collection
    Bonjour,

    J'essaie désespérément de créer une collection de collections, en gérant trois variables :
    - Ville,
    - Rue,
    - Habitant.

    L'idée est ensuite de pouvoir avoir une arborescence de ce type : Ville("Metz").Rue("De l'école").Habitant("Chez moi")
    Comme ce que fait Excel avec les classeurs, feuilles et cellules.

    J'arrive bien à créer des classes pour Ville, Rue et Habitant, mais elles sont indépendantes et je n'arrive pas à les faire dépendre les unes des autres.

    Est-ce que quelqu'un peut m'aider ? Ou me renvoyer vers un tuto déjà fait (je n'en ai pas trouvé) ?

    Merci à tous,
    Dominique

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

    Informations forums :
    Inscription : Juillet 2006
    Messages : 1 466
    Par défaut
    Salut,

    L'idée est d'encapsuler une collection dans une classe.
    La classe devra renvoyer via une propriété ou une méthode, le type désiré (natif ou une autre classe).
    Le plus simple est de commencer par la classe la plus profonde dans la hiérarchie.

    Il faut également se demander quels services la classe devra fournir.
    Comment l'initialiser ?
    Comment ajouter des éléments ?
    Comment accéder aux éléments ?
    Doit on pouvoir itérer sur les éléments ?

    Peux-tu poster les sources sur ce que tu as déja fait ?

  3. #3
    Rédacteur/Modérateur


    Homme Profil pro
    Formateur et développeur chez EXCELLEZ.net
    Inscrit en
    Novembre 2003
    Messages
    19 125
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 58
    Localisation : Belgique

    Informations professionnelles :
    Activité : Formateur et développeur chez EXCELLEZ.net
    Secteur : Enseignement

    Informations forums :
    Inscription : Novembre 2003
    Messages : 19 125
    Billets dans le blog
    131
    Par défaut
    Bonjour.

    Il y a bien mon tuto sur les classes : https://fauconnier.developpez.com/ar...neral/classes/

    Cela dit, je voudrais d'abord mieux comprendre ce que tu souhaites obtenir. Tu parles de collection de collections, mais je ne suis pas certain d'avoir compris.

    Tu veux des "poupées russes"? Villes => Ville => Rues => Rue => Habitants => Habitant? Si oui, peux-tu montrer comment sont organisées tes données dans Excel?

    Peux-tu aussi renseigner ta version d'Excel?

    Le problème peut être abordé en procédural ou via des classes. Avec quoi te sens-tu le mieux à l'aise?
    "Plus les hommes seront éclairés, plus ils seront libres" (Voltaire)
    ---------------
    Mes billets de blog sur DVP
    Mes remarques et critiques sont purement techniques. Ne les prenez jamais pour des attaques personnelles...
    Pensez à utiliser les tableaux structurés. Ils vous simplifieront la vie, tant en Excel qu'en VBA ==> mon tuto
    Le VBA ne palliera jamais une mauvaise conception de classeur ou un manque de connaissances des outils natifs d'Excel...
    Ce ne sont pas des bonnes pratiques parce que ce sont les miennes, ce sont les miennes parce que ce sont des bonnes pratiques
    VBA pour Excel? Pensez D'ABORD en EXCEL avant de penser en VBA...
    ---------------

  4. #4
    Futur Membre du Club
    Homme Profil pro
    Chargé d'affaire
    Inscrit en
    Janvier 2024
    Messages
    5
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Chargé d'affaire

    Informations forums :
    Inscription : Janvier 2024
    Messages : 5
    Par défaut
    Bonjour,

    Merci pour l'intérêt que vous portez à mon problème.

    @Pierre : Oui, je cherche à faire des poupées russes. J'avais utilisé votre tuto pour commencer, mais je bloque. Je n'arrive pas à imbriquer les éléments.

    J'avais illustré ma recherche avec les rues, mais c'est pour une application concrète de calcul sur des données :
    - J'ai différents capteurs avec des informations à stocker (marque, modèle, ...), --> les Villes
    - Chaque capteur est régulièrement étalonné (juste l'info de la date d'étalonnage), --> les Rues
    - Chaque étalonnage nous donne des coefficients (3 dans mon cas). --> les Habitants

    J'ai un tableau Excel de ce genre, avec près de 1000 lignes. J'ai fait une macro qui fonctionne, en manipulant des tableaux, mais ce n'est pas joli. Je cherche donc une méthode propre pour progresser en VBA Excel. Je suis certain qu'il existe des solutions bien plus faciles et propres.
    A partir de la ligne 10, j'ai mis le type d'organisation que je recherche.

    Nom : Données.png
Affichages : 279
Taille : 23,1 Ko

    J'ai ce petit bout de programme qui me permet de créer mes capteurs avec un tableau. Cette partie marche.
    J'ai voulu mettre un tableau pour les étalonnages, mais ça ne veut pas fonctionner (ligne en commentaire).
    Dans un premier temps, j'ai donc essayé de simplifier en ne mettant pas un tableau, mais en considérant un étalonnage unique. Même là, ça ne marche pas. Je n'arrive pas a affecter une valeur pour la date d'étalonnage.

    Je pense que je me perds dans les méandres des objets. J'ai vraiment envie de comprendre car cela fait plusieurs fois que je reprends ce sujet, mais je suis toujours bloqué malgré de nombreuses recherches sur internet.

    Macro
    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
    Private Sub CreerClient()
        Dim oCapteur(10) As clsCapteur
        Dim i As Integer
     
        For i = 1 To 3
            Set oCapteur(i) = New clsCapteur
        Next i
     
        oCapteur(1).sID = "1002"
        oCapteur(1).sMarque = "Dupond"
        oCapteur(1).sModele = "Carré"
     
        'Set oEtalonnage = New clsEtalonnage
        Set oCapteur(1).oEtalonnage = New clsEtalonnage
     
        'Set oCapteur(1).oEtalonnage(1) = New clsEtalonnage
     
        'Impossible d'affecter une valeur
        'oCapteur(1).oEtalonnage.sDate = "Jour"
     
        Debug.Print (oCapteur(1).sID)
        Debug.Print (oCapteur(1).sMarque)
        Debug.Print (oCapteur(1).sModele)
     
    End Sub
    Classe clsCapteur
    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
    Private mID As String
    Private mMarque As String
    Private mModele As String
    'Private mEtalonnage(5) As clsEtalonnage
    Private mEtalonnage As clsEtalonnage
     
    'Public Property Set oEtalonnage(byval oEtalonnage As clsEtalonnage)
    '    Set mEtalonnage = oEtalonnage()
    'End Property
     
    Public Property Set oEtalonnage(ByVal oEtalonnage As clsEtalonnage)
        Set mEtalonnage = oEtalonnage
    End Property
     
    Public Property Let sID(ByVal sID As String)
        mID = sID
    End Property
     
    Public Property Get sID() As String
        sID = mID
    End Property
     
    Public Property Let sMarque(ByVal sMarque As String)
        mMarque = sMarque
    End Property
     
    Public Property Get sMarque() As String
        sMarque = mMarque
    End Property
     
    Public Property Let sModele(ByVal sModele As String)
        mModele = sModele
    End Property
     
    Public Property Get sModele() As String
        sModele = mModele
    End Property
    Classe clsEtalonnage
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    Private mDate As String
     
    Public Property Let sDate(ByVal sDate As String)
        mDate = sDate
    End Property
     
    Public Property Get sDate() As String
        sDate = mDate
    End Property

  5. #5
    Rédacteur/Modérateur


    Homme Profil pro
    Formateur et développeur chez EXCELLEZ.net
    Inscrit en
    Novembre 2003
    Messages
    19 125
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 58
    Localisation : Belgique

    Informations professionnelles :
    Activité : Formateur et développeur chez EXCELLEZ.net
    Secteur : Enseignement

    Informations forums :
    Inscription : Novembre 2003
    Messages : 19 125
    Billets dans le blog
    131
    Par défaut
    Version d'Excel?
    "Plus les hommes seront éclairés, plus ils seront libres" (Voltaire)
    ---------------
    Mes billets de blog sur DVP
    Mes remarques et critiques sont purement techniques. Ne les prenez jamais pour des attaques personnelles...
    Pensez à utiliser les tableaux structurés. Ils vous simplifieront la vie, tant en Excel qu'en VBA ==> mon tuto
    Le VBA ne palliera jamais une mauvaise conception de classeur ou un manque de connaissances des outils natifs d'Excel...
    Ce ne sont pas des bonnes pratiques parce que ce sont les miennes, ce sont les miennes parce que ce sont des bonnes pratiques
    VBA pour Excel? Pensez D'ABORD en EXCEL avant de penser en VBA...
    ---------------

  6. #6
    Futur Membre du Club
    Homme Profil pro
    Chargé d'affaire
    Inscrit en
    Janvier 2024
    Messages
    5
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Chargé d'affaire

    Informations forums :
    Inscription : Janvier 2024
    Messages : 5
    Par défaut
    Citation Envoyé par Pierre Fauconnier Voir le message
    Version d'Excel?
    J'ai la version de 2007 (c'est pas très récent).

    Dominique

  7. #7
    Rédacteur/Modérateur


    Homme Profil pro
    Formateur et développeur chez EXCELLEZ.net
    Inscrit en
    Novembre 2003
    Messages
    19 125
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 58
    Localisation : Belgique

    Informations professionnelles :
    Activité : Formateur et développeur chez EXCELLEZ.net
    Secteur : Enseignement

    Informations forums :
    Inscription : Novembre 2003
    Messages : 19 125
    Billets dans le blog
    131
    Par défaut
    Citation Envoyé par DomDeGre Voir le message
    J'ai la version de 2007 (c'est pas très récent).

    Dominique
    Pas grave. Le VBA n'a pas évolué depuis. C'est juste pour montrer du code d'alimentation des collections qui peut être reproduit dans ta version.
    "Plus les hommes seront éclairés, plus ils seront libres" (Voltaire)
    ---------------
    Mes billets de blog sur DVP
    Mes remarques et critiques sont purement techniques. Ne les prenez jamais pour des attaques personnelles...
    Pensez à utiliser les tableaux structurés. Ils vous simplifieront la vie, tant en Excel qu'en VBA ==> mon tuto
    Le VBA ne palliera jamais une mauvaise conception de classeur ou un manque de connaissances des outils natifs d'Excel...
    Ce ne sont pas des bonnes pratiques parce que ce sont les miennes, ce sont les miennes parce que ce sont des bonnes pratiques
    VBA pour Excel? Pensez D'ABORD en EXCEL avant de penser en VBA...
    ---------------

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

    Informations forums :
    Inscription : Juillet 2006
    Messages : 1 466
    Par défaut
    Ce que tu recherche n'est ils pas des collections fortement typées ?
    https://nolongerset.com/strongly-typ...ctions-in-vba/

  9. #9
    Futur Membre du Club
    Homme Profil pro
    Chargé d'affaire
    Inscrit en
    Janvier 2024
    Messages
    5
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Chargé d'affaire

    Informations forums :
    Inscription : Janvier 2024
    Messages : 5
    Par défaut
    Citation Envoyé par deedolith Voir le message
    Ce que tu recherche n'est ils pas des collections fortement typées ?
    https://nolongerset.com/strongly-typ...ctions-in-vba/
    Merci pour le lien., mais ce n'est pas ce que je recherche. Dans ce cas, il faudrait une catégorie Ford uniquement, qui regroupe ensuite tous les modèles.
    Dans mon fichier Excel, mes lignes ne sont pas indépendantes. Entre la ligne 1 et 2, c'est le même capteur. Je ne veux rentrer ses informations générales (ID, marque, modèle, ...) qu'une seule fois. Ensuite, dans une sous catégorie, je souhaite rentrer les dates d'étalonnages, avec les coefficients qui vont avec.

    Je gère ensuite ces données un peu dans tous les sens pour les mettre à jour, en ajouter, générer des fichiers de configuration et suivre le comportement dans le temps d'un capteur ou d'un lot de capteur, ...

    L'organisation dans Excel entre les classeurs, feuilles et cellules correspond à ce que je recherche.

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

    Informations forums :
    Inscription : Juillet 2006
    Messages : 1 466
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    'Set oCapteur(1).oEtalonnage(1) = New clsEtalonnage
    Il te manque un Property Get qui retourne un objet de type clsEtalonnage.

    PS:
    Abandonne la notation hongroise, ca n'apporte rien de bon et nuit à la lisibilité / compréhension plus qu'autre chose.
    Les noms de variable doivent refléter leur rôle, un type n'est pas un rôle.
    Les types ne sont utiles que pour le compilateur, pour l'humain c'est le sens qui prime.
    Jette un coup d'oeil dans l'explorateur d'objet, cette technique (inutile) n'est utilisé nulle part.

  11. #11
    Rédacteur/Modérateur


    Homme Profil pro
    Formateur et développeur chez EXCELLEZ.net
    Inscrit en
    Novembre 2003
    Messages
    19 125
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 58
    Localisation : Belgique

    Informations professionnelles :
    Activité : Formateur et développeur chez EXCELLEZ.net
    Secteur : Enseignement

    Informations forums :
    Inscription : Novembre 2003
    Messages : 19 125
    Billets dans le blog
    131
    Par défaut
    Salut.

    Voici comment je coderais cela.

    Une classe cCapteur. Id, Marque et Modele sont des propriétés en lecture/écriture et le code de la classe ne doit pas les modifier. On peut donc les déclarer comme je l'ai fait en entête de module. La classe offre une collection d'étalonnages (cEtalonnage) et une fonction pour charger un étalonnage dans la collection
    Code vba : 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
     
    Public Id As Long
    Public Marque As String
    Public Modele As String
     
    Private mEtalonnages As Collection
     
    Property Get Etalonnages() As Collection
      Set Etalonnages = mEtalonnages
    End Property
     
    Function AjouterEtalonnage(Etalonnage As cEtalonnage)
      If mEtalonnages Is Nothing Then Set mEtalonnages = New Collection
      Etalonnage.Capteur = Me
      mEtalonnages.Add Etalonnage
    End Function

    Une classe cEtalonnage. Là aussi, DateEtalonnage, Coefficient1 et Coefficient2 sont des propriétés en lecture/écriture sans modifications dans la classe. On n'est donc pas obligé de les déclarer via Property Get et Property Set. On passe le capteur auquel se rapporte le coéfficient. Ici, bien que le capteur n'est pas modifié par la classe, on passe par des Property pour éviter l'emploi de Set dans le code appelant.
    Code vba : 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
     
    Public DateEtalonnage As Date
    Public Coefficient1 As Double
    Public Coefficient2 As Double
     
    Private mCapteur As cCapteur
     
    Property Get Capteur() As cCapteur
      Set Capteur = mCapteur
    End Property
     
    Property Let Capteur(Capteur As cCapteur)
      Set mCapteur = Capteur
    End Property

    Par rapport à un tableau de données (une table) qui reprend les données des étalonnages et qui s'appelle t_Etalonnages, on peut charger les objets avec le code suivant. Test Est la proc principale, et elle utilise deux fonctions qui renvoie un capteur et un étalonnage en fonction de l'indice de ligne passé.
    Code vba : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    Option Explicit
     
    Sub Test()
      Dim Capteurs As Collection
      Dim Capteur As cCapteur
      Dim Etalonnage As cEtalonnage
      Dim i As Long: i = 1
      Dim Id As Long
     
      Set Capteurs = New Collection
      Set Capteur = NouveauCapteur(i)
      Capteurs.Add Capteur
      Do While i <= Range("t_Etalonnages").Rows.Count
        If Range("t_Etalonnages[id]")(i).Value = Capteur.Id Then
          Set Etalonnage = NouvelEtalonnage(i)
          Capteur.AjouterEtalonnage Etalonnage
          i = i + 1
        Else
          Set Capteur = NouveauCapteur(i)
          Capteurs.Add Capteur
        End If
      Loop
    End Sub
     
    Function NouveauCapteur(i As Long) As cCapteur
      Set NouveauCapteur = New cCapteur
      With NouveauCapteur
        .Id = Range("t_etalonnages[id]")(i).Value
        .Marque = Range("t_etalonnages[Marque]")(i).Value
        .Modele = Range("t_etalonnages[Modèle]")(i).Value
      End With
    End Function
     
    Function NouvelEtalonnage(i As Long) As cEtalonnage
      Set NouvelEtalonnage = New cEtalonnage
      With NouvelEtalonnage
        .DateEtalonnage = Range("t_etalonnages[Etalonnage]")(i).Value
        .Coefficient1 = Range("t_etalonnages[coefficient 1]")(i).Value
        .Coefficient2 = Range("t_etalonnages[coefficient 2]")(i).Value
      End With
    End Function

    Nom : 2024-01-21_113447.png
Affichages : 247
Taille : 24,7 Ko
    "Plus les hommes seront éclairés, plus ils seront libres" (Voltaire)
    ---------------
    Mes billets de blog sur DVP
    Mes remarques et critiques sont purement techniques. Ne les prenez jamais pour des attaques personnelles...
    Pensez à utiliser les tableaux structurés. Ils vous simplifieront la vie, tant en Excel qu'en VBA ==> mon tuto
    Le VBA ne palliera jamais une mauvaise conception de classeur ou un manque de connaissances des outils natifs d'Excel...
    Ce ne sont pas des bonnes pratiques parce que ce sont les miennes, ce sont les miennes parce que ce sont des bonnes pratiques
    VBA pour Excel? Pensez D'ABORD en EXCEL avant de penser en VBA...
    ---------------

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

    Informations forums :
    Inscription : Juillet 2006
    Messages : 1 466
    Par défaut
    @Pierre Fauconnier:

    Cette conception pose plusieurs problèmes.
    Les propriétés sont accessibles en lecture / écriture, sans restrictions (viol du principe d'encapsulation).
    Les éléments des collections sont faiblement typés (des variants).
    Pour être fonctionnelle, elle se base sur la rigueur et la discipline du développeur, ce qui est source d'erreurs.

    Qu'est ce qui interdit d'écrire:
    Capteurs.Add New cEtalonnage
    Rien du tout, et l'erreur ne sera signalée qu'a l'exécution, soit trop tard.
    On peut faire mieux, en signalant les erreurs plus tôt: A la compilation.
    Pour cela, il faut comprendre les concepts de Factory, et collection fortement typée.

    Factory:
    L'idée repose sur le fait qu'a l'instanciation, un objet doit être directement utilisable, sans qu'il soit nécessaire de procéder à des initialisations supplémentaire (l'instanciation doit se suffire à elle même).
    Malheureusement, VBA n'offre que peut de mécanique pour implémenter ce comportement, faute de possibilité de surcharger les fonctions membres, dont le constructeur (qui est unique et sans paramètres).
    Mais, tout n'est pas perdu, avec une Factory, comprendre: Un "machin" en charge de créer (instancier / initialiser) des objets.
    On va commencer par écrire un pseudo constructeur, qui ne sera appelé que par la Factory.
    La Factory, sera une classe ou un module standard, possédant des fonctions, chacune renvoyant un objet du type désiré, et possédant tous les paramètres nécessaires à son initialisation (perso: Je préfère un module standard).
    Illustration:
    Pour cet exemple, on a prendre une classe Automobile.
    Une Automobile à un marque, un modèle et une couleur.
    La marque et le modèle ne sont pas modifiables.
    On peut la repeindre.
    Par défaut, sa couleur est blanche.
    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
    Option Explicit
     
    Private mMarque As String
    Private mModele As String
    Private mCouleur As String
     
        '// Pseudo constructeur, initialise l'objet
    Friend Sub Create(ByVal Marque As String, ByVal Modele As String, ByVal Couleur As String)
        mMarque = Marque
        mModele = Modele
        mCouleur = Couleur
    End Sub
     
        '// Propriétés, en lecture seule
        '// Modifier la marque et le modèle d'une voiture n'a pas de sens
    Public Property Get Marque() As String
        Marque = mMarque
    End Property
     
    Public Property Get Modele() As String
        Modele = mModele
    End Property
     
        '// Propriété en lecture / ecriture
        '// On peut repeindre une voiture
    Public Property Get Couleur() As String
        Couleur = mCouleur
    End Property
     
    Public Property Let Couleur(ByVal Value As String)
        mCouleur = Value
    End Sub
    Le module Factory:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    Option Explicit
     
        '// Fonction en charge de créer une voiture
        '// L'argument Couleur enforce la valeur par defaut (si besoin).
    Public Function CreateAutomobile(ByVal Marque As String, ByVal Modele As String, Optional ByVal Couleur As String = "Blanche") As Automobile
        Dim Voiture As Voiture
        Set Voiture = New Voiture
        Voiture.Create Marque, Modele, Couleur    '// appel du pseudo constructeur
        Set CreateVoiture = Voiture
    End Function
    Et Enfin, dans un module standard, une fonction de test:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    Option Explicit
     
    Public Sub Test()
        Dim Peugeot205 As Automobile
        Set Peugeot205 = Factory.CreateAutomobile("Peugeot", "205")    '// Ok, la couleur est blanche
     
        Peugeot205.Couleur = "Noir"    '// Ok, on peut la repeindre
        Peugeot205.Marque = "Renault"    '// Erreur de compilation, la propriété Marque est en lecture seule.
    End Sub
    Conclusion:
    L'utilisation de la classe s'en trouve renforcée.
    Les erreurs de programmation sont signalées à la compilation et non à l'execution.
    La construction des objets étant déléguée ailleur, cela facilite la lecture et compréhension du code source.
    Certes, on a toujours un bout de code qui procède à l'initialisation (impossible de s'en séparer), mais il est encapsulé dans une fonction à part. Ce n'est au final qu'un sordide détail d'implémentation.

    Je ne détaillerai pas le concept de collection fortement typée, j'ai déjà posté un lien ers un tutoriel.

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

    Informations forums :
    Inscription : Juillet 2006
    Messages : 1 466
    Par défaut
    Notes supplémentaires:

    Le modèle ci dessus est améliorable.
    En effet, le pseudo constructeur étant ami (mot clef: Friend, c'est a dire qu'il n'est appelable qu'au sein du projet où la classe est définie), il est possible de l'appeler plusieurs fois, ce qui revient à réinitialiser l'objet, comportement qui n'est pas souhaitable (ce n'est pas son rôle).

    On peut enforcer la non réinitialisation avec une variable un indicateur statique qui signalisera que l'objet à déjà été construit et une assertion:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    Friend Sub Create(ByVal Marque As String, ByVal Modele As String, ByVal Couleur As String)
        Static Created As Boolean
        Debug.Assert Not Created    '// L'objet a déjà été instancié
                                    '// Veuillez utiliser Factory.CreateAutomobile pour instancier un nouvel objet
        Created = True
     
        mMarque = Marque
        mModele = Modele
        mCouleur = Couleur
    End Sub
    Si le besoin se fait sentir de réinitialiser l'objet, on peut au choix:
    - Ecraser l'instance courrante avec une nouvelle (via la factory).
    - Fournir une méthode de réinitialisation (à condition que cela aie du sens).

  14. #14
    Rédacteur/Modérateur


    Homme Profil pro
    Formateur et développeur chez EXCELLEZ.net
    Inscrit en
    Novembre 2003
    Messages
    19 125
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 58
    Localisation : Belgique

    Informations professionnelles :
    Activité : Formateur et développeur chez EXCELLEZ.net
    Secteur : Enseignement

    Informations forums :
    Inscription : Novembre 2003
    Messages : 19 125
    Billets dans le blog
    131
    Par défaut
    Je pense qu'il faut se mettre au niveau du besoin et qu'il n'est pas nécessaire d'être puriste.

    Passer par des Property juste pour échanger les valeurs entre l'objet et le code appelant ne sert à rien. Je ne vois pas en quoi déclarer les propriétés comme je l'ai fait enfreint les règles d'encapsulation.

    De plus les classes sont privées et donc liées intimement au projet. On n'est pas ici dans le cadre de classes que l'on crée dans des frameworks.

    Pas certain donc qu'il soit nécessaire de pousser si loin.

    De plus c'est une proposition de code que l'on peut évidemment adapter.
    "Plus les hommes seront éclairés, plus ils seront libres" (Voltaire)
    ---------------
    Mes billets de blog sur DVP
    Mes remarques et critiques sont purement techniques. Ne les prenez jamais pour des attaques personnelles...
    Pensez à utiliser les tableaux structurés. Ils vous simplifieront la vie, tant en Excel qu'en VBA ==> mon tuto
    Le VBA ne palliera jamais une mauvaise conception de classeur ou un manque de connaissances des outils natifs d'Excel...
    Ce ne sont pas des bonnes pratiques parce que ce sont les miennes, ce sont les miennes parce que ce sont des bonnes pratiques
    VBA pour Excel? Pensez D'ABORD en EXCEL avant de penser en VBA...
    ---------------

  15. #15
    Membre Expert Avatar de Thumb down
    Homme Profil pro
    Retraité
    Inscrit en
    Juin 2019
    Messages
    1 560
    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 560
    Par défaut
    Bonjour,
    je me suis inspiré du tableau de Pierre; je n'est pas utilisé de propriétés car je n'en est pas vu l'intérêt dans le contexte!

    j'ai créé 3 module de classe et un module standard
    1. Module1
      Code : Sélectionner tout - Visualiser dans une fenêtre à part
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      Sub test()
      Dim Maitres As New Maitre, I As Integer
      With Range("Tableau1")
          For I = 2 To .Rows.Count
              Maitres.Add .Cells(I, "A"), .Cells(I, "B"), .Cells(I, "C"), .Cells(I, "D"), .Cells(I, "E"), .Cells(I, "F")
          Next
      End With
      Dim T() As String
      T() = Maitres.RetourneTableau
      Range("J1").Resize(UBound(T, 1), UBound(T, 2) + 1) = T
      End Sub
    2. Maitre qui est le point d'entré
      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
      Private Capteurs As New Collection, Keys As String, L As IntegerPrivate
       Function Existe(Key As String) As Boolean
      
      Existe = InStr(1, "©" & Keys & "©", "©" & Key & "©")
      End Function
      Public Sub Add(ID As String, Marque As String, Modele As String, Etalonnage As String, Coeficient1 As String, Coeficient2 As String)
      If Not Existe(ID) Then
          Capteurs.Add New Capteur, CStr(ID)
          Keys = Keys & "©" & ID & "©"
      End If
      Capteurs(ID).Add ID, Marque, Modele, Etalonnage, Coeficient1, Coeficient2, L
      End Sub
      Public Function RetourneTableau() As String()
      Dim Cls As Capteur, T() As String, R As Integer
      ReDim T(L, 3)
      For Each Cls In Capteurs
          Cls.RetourneTableau T, R
      Next
      RetourneTableau = T
      End Function
      Private Sub Class_Initialize()
      L = 1
      End Sub
      Private Sub Class_Terminate()
      Set Capteurs = Nothing
      End Sub
    3. Capteur
      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
      Private Keys As String, Etalonnages As New CollectionPrivate ID_ As String, Marque_ As String, Modele_ As String
      Private Function Existe(Key As String) As Boolean
      
      Existe = InStr(1, "©" & Keys & "©", "©" & Key & "©")
      End Function
      Public Sub Add(ID As String, Marque As String, Modele As String, Etalon As String, Coeficient1 As String, Coeficient2 As String, L As Integer)
       ID_ = ID: Marque_ = Marque: Modele_ = Modele
      If Not Existe(Format(Etalon, "yyyy-mm-dd")) Then
         Etalonnages.Add New Etalonnage, Format(Etalon, "yyyy-mm-dd")
          Keys = Keys & "©" & Format(Etalon, "yyyy-mm-dd") & "©"
      End If
      Etalonnages(Format(Etalon, "yyyy-mm-dd")).Add Format(Etalon, "yyyy-mm-dd"), Coeficient1, Coeficient2, L
      L = L + 1
      End Sub
      Public Sub RetourneTableau(T() As String, R As Integer)
          T(R, 0) = ID_ & "," & Marque_ & "," & Modele_
          Dim Cls As Etalonnage
        For Each Cls In Etalonnages
          Cls.RetourneTableau T, R
         Next
           R = R + 1
      End Sub
      Private Sub Class_Initialize()
      Set Etalonnages = Nothing
      End Sub
    4. Etalonnage
      Code : Sélectionner tout - Visualiser dans une fenêtre à part
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      Private Etalonnage_ As String, Coeficient1_ As String, Coeficient2_ As StringPrivate
       Public Sub Add(Etalonnage As String, Coeficient1 As String, Coeficient2 As String, L As Integer)
      Etalonnage_ = Etalonnage: Coeficient1_ = Coeficient1: Coeficient2_ = Coeficient2
      L = L + 1
      End Sub
      Public Sub RetourneTableau(T() As String, R As Integer)
      R = R + 1
          T(R, 0) = "|->": T(R, 1) = CDate(Etalonnage_)
      R = R + 1: T(R, 0) = "|": T(R, 1) = "|->": T(R, 2) = Coeficient1_: T(R, 3) = Coeficient2_
      End Sub
      Nom : Sans titre.png
Affichages : 237
Taille : 129,1 Ko
    Fichiers attachés Fichiers attachés

  16. #16
    Rédacteur/Modérateur


    Homme Profil pro
    Formateur et développeur chez EXCELLEZ.net
    Inscrit en
    Novembre 2003
    Messages
    19 125
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 58
    Localisation : Belgique

    Informations professionnelles :
    Activité : Formateur et développeur chez EXCELLEZ.net
    Secteur : Enseignement

    Informations forums :
    Inscription : Novembre 2003
    Messages : 19 125
    Billets dans le blog
    131
    Par défaut
    deedolith

    Pour info. FRIEND n'existe pas en vba
    "Plus les hommes seront éclairés, plus ils seront libres" (Voltaire)
    ---------------
    Mes billets de blog sur DVP
    Mes remarques et critiques sont purement techniques. Ne les prenez jamais pour des attaques personnelles...
    Pensez à utiliser les tableaux structurés. Ils vous simplifieront la vie, tant en Excel qu'en VBA ==> mon tuto
    Le VBA ne palliera jamais une mauvaise conception de classeur ou un manque de connaissances des outils natifs d'Excel...
    Ce ne sont pas des bonnes pratiques parce que ce sont les miennes, ce sont les miennes parce que ce sont des bonnes pratiques
    VBA pour Excel? Pensez D'ABORD en EXCEL avant de penser en VBA...
    ---------------

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

    Informations forums :
    Inscription : Juillet 2006
    Messages : 1 466
    Par défaut
    Citation Envoyé par Pierre Fauconnier Voir le message
    deedolith

    Pour info. FRIEND n'existe pas en vba
    Faux !!! ... je te donne mes sources:
    https://learn.microsoft.com/fr-fr/of...friend-keyword

  18. #18
    Rédacteur/Modérateur


    Homme Profil pro
    Formateur et développeur chez EXCELLEZ.net
    Inscrit en
    Novembre 2003
    Messages
    19 125
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 58
    Localisation : Belgique

    Informations professionnelles :
    Activité : Formateur et développeur chez EXCELLEZ.net
    Secteur : Enseignement

    Informations forums :
    Inscription : Novembre 2003
    Messages : 19 125
    Billets dans le blog
    131
    Par défaut
    Ok. Au temps pour moi. Je pensais que cela n'était apparu que sur dot.net.

    Mais, qu'est-ce que cela apporte au projet dont il est question ici? Friend fait que l'on ne peut utiliser la propriété que dans le projet qui contient la classe qui contient la propriété déclarée en Friend. Ça tombe bien. On est dans le même projet, et il n'est nulle part question, dans la demande initiale, de créer des classes publiques (qui peuvent être utilisées par un autre projet).

    Donc, Friend n'a rien à faire ici et n'apporte rien de plus au projet.



    Quant au design pattern Factory, que l'on peut modéliser en VBA, avec de la rigueur en programmation, il n'apporte pas grand-chose ici. Mais de toute manière, il est "modélisé" dans mon exemple puisque tant le capteur que l'étalonnage sont créés par des fonctions spécifiques. Il suffit de les déporter dans un module standard nommé Factory et hop, on a notre Design Pattern Factory "plus formel". On ne pourra pas aller beaucoup plus loin que cela en VBA.

    Il en est de même avec les collections fortement typées. Dans le cas prévu ici, on ne chargera jamais la collection des étalonnages dans un capteur avec autre chose que des objets issus de cEtalonnage, puisque la fonction AjouterEtalonnage requiert que l'on passe un objet cEtalonnage.

    Restons pragmatiques pour ne pas noyer le lecteur et le demandeur dans des concepts qui n'apportent rien à la demande initiale et qui en plus sont implémentés, à tout le moins de façon implicite.
    "Plus les hommes seront éclairés, plus ils seront libres" (Voltaire)
    ---------------
    Mes billets de blog sur DVP
    Mes remarques et critiques sont purement techniques. Ne les prenez jamais pour des attaques personnelles...
    Pensez à utiliser les tableaux structurés. Ils vous simplifieront la vie, tant en Excel qu'en VBA ==> mon tuto
    Le VBA ne palliera jamais une mauvaise conception de classeur ou un manque de connaissances des outils natifs d'Excel...
    Ce ne sont pas des bonnes pratiques parce que ce sont les miennes, ce sont les miennes parce que ce sont des bonnes pratiques
    VBA pour Excel? Pensez D'ABORD en EXCEL avant de penser en VBA...
    ---------------

  19. #19
    Rédacteur/Modérateur


    Homme Profil pro
    Formateur et développeur chez EXCELLEZ.net
    Inscrit en
    Novembre 2003
    Messages
    19 125
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 58
    Localisation : Belgique

    Informations professionnelles :
    Activité : Formateur et développeur chez EXCELLEZ.net
    Secteur : Enseignement

    Informations forums :
    Inscription : Novembre 2003
    Messages : 19 125
    Billets dans le blog
    131
    Par défaut
    @Thumb Down

    Perso, je ne coderais pas les classes comme tu l'as fait. C'est incohérent pour moi de passer les données d'étalonnage dans l'init du capteur. Ça oblige à avoir les données de l'étalonnage au moment de la création du capteur, ce qui est contraignant. On doit pouvoir créer le capteur indépendamment de tout étalonnage.

    Pas d'accord non plus de prévoir la sortie du tableau dans la classe de l'étalonnage, car cela veut dire que l'on ne peut sortir les données de l'étalonnage que comme ça, alors qu'on pourrait devoir les sortir autrement.

    De plus, que ce soit au niveau du capteur ou de l'étalonnage, ça n'a pas de cohérence de passer la date en string, pas plus que de passer par une troisième classe "Maitre" qui n'a pas de consistance dans les données manipulées. On est en face de capteurs et de données d'étalonnage, on doit donc avoir une classe qui modélise le capteur et une classe qui modélise l'étalonnage. La classe "Maitre" vient juste ajouter de l'inutilité et du brouillard dans le code.
    "Plus les hommes seront éclairés, plus ils seront libres" (Voltaire)
    ---------------
    Mes billets de blog sur DVP
    Mes remarques et critiques sont purement techniques. Ne les prenez jamais pour des attaques personnelles...
    Pensez à utiliser les tableaux structurés. Ils vous simplifieront la vie, tant en Excel qu'en VBA ==> mon tuto
    Le VBA ne palliera jamais une mauvaise conception de classeur ou un manque de connaissances des outils natifs d'Excel...
    Ce ne sont pas des bonnes pratiques parce que ce sont les miennes, ce sont les miennes parce que ce sont des bonnes pratiques
    VBA pour Excel? Pensez D'ABORD en EXCEL avant de penser en VBA...
    ---------------

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

    Informations forums :
    Inscription : Juillet 2006
    Messages : 1 466
    Par défaut
    Citation Envoyé par Pierre Fauconnier Voir le message
    Mais, qu'est-ce que cela apporte au projet dont il est question ici? Friend fait que l'on ne peut utiliser la propriété que dans le projet qui contient la classe qui contient la propriété déclarée en Friend. Ça tombe bien. On est dans le même projet, et il n'est nulle part question, dans la demande initiale, de créer des classes publiques (qui peuvent être utilisées par un autre projet).

    Quant au design pattern Factory, que l'on peut modéliser en VBA, avec de la rigueur en programmation, il n'apporte pas grand-chose ici....

    Il en est de même avec les collections fortement typées.
    Concernant le mot clef Friend:
    Je t'invite à prendre du recule, et développer des bibliothèques re-utilisables. Son utilisation prendra tout son sens.
    Ensuite, c'est une bonne habitude que j'ai pris (ce qui ne fait jamais de mal).

    Concernant le design pattern Factory:
    L'idée est d'une part, de décorréler l'instanciation des objets (minimiser les dépendances).
    D'autre part, obtenir des classes au comportement cohérent.
    Apporter des garanties (laisser en lecture seule ce qui a besoin de l'être).
    Détecter les erreurs de programmation au plus tôt (lors de la compilation).

    Concernant les collections fortement typées:
    Leur avantage est que l'on a la garantie que l'on ne peut y ajouter que des élément d'un type précis.
    On a également la garantie que les éléments contenus sont du type attendu.
    A mon sens, Il est préférable de s'appuyer sur des garanties que la discipline humaine.
    Bonus: Le type des éléments étant connu du compilateur, la saisie prédictive nous viendra en aide.

    Encore une fois, le but de tout cela est d'éviter les erreurs de programmation le plus tôt possible.
    Certes, cela demande plus de réflexion en amont, mais les garanties apportées maintiennent la cohérence et facilitent l'utilisation des objets.
    Au final: Un effort pour de grands bénéfices.

Discussions similaires

  1. []Erreur sur second emploi collection binding
    Par jacma dans le forum VB 6 et antérieur
    Réponses: 2
    Dernier message: 08/03/2004, 18h02
  2. [VB6] Sauvegarder une collection d'objets
    Par Sayagh dans le forum VB 6 et antérieur
    Réponses: 7
    Dernier message: 19/09/2003, 11h58
  3. [VB6] la collection controls
    Par tomnie dans le forum VB 6 et antérieur
    Réponses: 3
    Dernier message: 30/04/2003, 17h03
  4. Comment créér une collection sous Delphi
    Par PsyKroPack dans le forum Langage
    Réponses: 6
    Dernier message: 11/02/2003, 13h20
  5. [VB6] Modifier la clé d'un élément d'une collection
    Par Ricou13 dans le forum VB 6 et antérieur
    Réponses: 3
    Dernier message: 21/11/2002, 14h49

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