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

WinDev Discussion :

POO : classe CRUD générique [WD23]


Sujet :

WinDev

  1. #1
    Membre chevronné Avatar de wd_newbie
    Homme Profil pro
    Développeur
    Inscrit en
    Mars 2007
    Messages
    755
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Développeur
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2007
    Messages : 755
    Par défaut POO : classe CRUD générique
    Bonjour,

    j'en suis toujours à mes pérégrinations en POO sous Windev...

    Avec un peu (beaucoup !!) de patience, j'ai réussi à mettre en place quelques classes fonctionnelles, j'en suis aux méthodes CRUD pour la gestion des fichiers de données.

    Avec les indirections, j'ai pu créer les méthodes de façon générique pour les classes avec un mapping sur les données.
    Comme les méthodes sont génériques, je me suis fait des briques de code pour les ajouter aux classes de données.

    ça marche pas mal ... mais le code de ces classes est toujours le même à 90% ... donc je me dit qu'il devrait y avoir un moyen de peaufiner tous ça pour ne garder que le code "non standard" dans les classes liées aux données.

    L'idées serait une classe mère, par exemple "CCrud" qui contiendrait les méthodes d'ajout / suppression / ... et des classes filles qui hériteraient de CCrud, donc de ses méthodes d'accès aux données.

    Ler hic ... car bien entendu ça ne marche pas ... c'est que je ne trouve pas le moyen d'utiliser les méthodes de la "mère" avec les membres mappés de la "fille".

    Vraiment en gros, quelque chose dans le style :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
     
    classe CCrud est une classe 
    ...
     
    FIN 
     
    PROCEDURE Read(nID) : booléen
     
         HlitPremier({monFichier},{monFichier+"_ID", nID}
        FichierVers Mémoire({monFichier})
     
     
     
    MClients est une Classe <MAPPING=Clients>
    hérite de CCrud
    	// Le code se trouvant entre <MAPPING> et <FIN> est généré automatiquement.
    	// Il sera effacé et recréé entièrement à chaque génération depuis l'analyse.
    	<MAPPING>
    	m_nIDClients	est un entier sur 8 octets	<MAPPING=IDClients, clé unique>
    	m_sNom			est une chaîne ANSI			<MAPPING=Nom>
    	m_sPrenom		est une chaîne ANSI			<MAPPING=Prenom>
    	m_sRue			est une chaîne ANSI			<MAPPING=Rue>
    	m_sLocalite		est une chaîne ANSI			<MAPPING=Localite>
    	m_sNPA			est une chaîne ANSI			<MAPPING=NPA>
    	<FIN>
     
            m_Fichier est une chaine 
     
    FIN
     
    Constructeur (sFichier) 
     
        :m_Fichier = sFichier
     
    //*********************************
    //                  UTILISATION 
    //*********************************
     
    clTest est un MClient("T_Client")
    clTest.Read(123) 
    SourceVersEcran(clTest)

  2. #2
    Membre prolifique Avatar de Jon Shannow
    Homme Profil pro
    Responsable de service informatique
    Inscrit en
    Avril 2011
    Messages
    4 667
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Responsable de service informatique
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Avril 2011
    Messages : 4 667
    Par défaut
    Bonjour,

    Dans ta Méthode "read" tu fais un hlitpremier, alors que tu devrais faire un hlitrecherche.

    JS

  3. #3
    Membre chevronné Avatar de wd_newbie
    Homme Profil pro
    Développeur
    Inscrit en
    Mars 2007
    Messages
    755
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Développeur
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2007
    Messages : 755
    Par défaut
    Oui, c'est vrai, j'ai "créé" l'exemple de tête ...

    le retour n'est pas important, c'est la fonctionnalité reportée dans la classe mère qui ne fonctionne pas...

  4. #4
    Expert confirmé
    Avatar de Voroltinquo
    Homme Profil pro
    Chef de projet en SSII
    Inscrit en
    Juin 2017
    Messages
    2 933
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 59
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Chef de projet en SSII

    Informations forums :
    Inscription : Juin 2017
    Messages : 2 933
    Billets dans le blog
    1
    Par défaut
    Bonjour,
    L'astuce principale consiste à utiliser les mot clés MaCléUniqueMappé et MonFIchierMappé.
    Voici donc nos interfaces :
    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
     
    CRUD est une Interface
    	//L'affectation d'un tuple d'une table (Lecture) peut se faire lors de l'allocation
    	procédure CLit(pkIDClasse est entier sur 8)
    	procédure CAjoute()
    	procédure CModifie()
    	procédure CSupprime()						//Supprime l'enregistrement associé en cours
    	procédure CSupprime(pkIDClasse est entier sur 8)	//Supprime un enregistrement donné
    FIN
     
    RensMapping est une Interface
    	Propriété p_NomTable 	: chaîne 			<lecture>	//Récupère le nom de la table dont dépend la classe mappée
    	Propriété p_NomPK    	: chaîne 			<lecture>	//Récupère le nom de la PK de la table dont dépend la classe mappée
    	Propriété p_NomIDClasse 	: chaîne 			<lecture>	//Récupère le nom du membre associé à la PK
    	Propriété p_ValIDClasse 	: entier sur 8 		<lecture>	//Récupère la valeur de la PK
    FIN
    Comme tu le précisais, tes classes doivent hériter d'une classe générique dans laquelle seront définies les méthodes correspondant à l'interface CRUD

    Intéressons nous aux membres.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    MClient est une Classe <MAPPING=Client>
    	hérite de CGénérique
     
    	PRIVÉ
    		<MAPPING>
    			m_pkClient		est un entier sur 8 octets	<MAPPING=PK_Client, clé unique>
    			m_saNoClient	est une chaîne ANSI			<MAPPING=AK_NoClient>
    			m_saNomClient	est une chaîne ANSI			<MAPPING=NDX_NomClient>
    			m_saEtc_Client	est une chaîne ANSI			<MAPPING=Etc_Client>
    			m_saTypeClient	est une chaîne ANSI			<MAPPING=NDX_TypeClient>
    		<FIN>
     
    FIN
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    CGénérique est une Classe
    	implémente CRUD
    	implémente RensMapping
     
    PRIVÉ
    	m_pclTravail est un objet dynamique     //Objet qui va instancier une classe fille de CGénérique
    FIN
    Avec :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    PROCÉDURE Constructeur()
     
    //Surcharge 1
    PROCÉDURE Constructeur(saNomClasse est chaîne)
    :m_pclTravail=allouer un saNomClasse
     
    //Surcharge 2
    PROCÉDURE Constructeur(saNomClasse est chaîne, pkIDClasse est entier sur 8)
    :m_pclTravail=allouer un saNomClasse
    HLitRecherchePremier(:p_NomTable,:p_NomPK,pkIDClasse)
    FichierVersMémoire(:m_pclTravail,:p_NomTable)
    Passons maintenant aux getters définis dans RensMapping
    Ces getters sont de 2 types, celles implémentées dans les filles et celles utilisées dans CGénérique.
    Getter des classes filles
    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
     
    FONCTION p_NomPK() : chaîne
    RENVOYER MaCléUniqueMappée
     
    FONCTION p_NomTable() : chaîne
    RENVOYER MonFichierMappé
     
    FONCTION p_NomIDClasse() : chaîne
    //Le code qui suit est valable à partir de WD28 grâce à l'introduction des propriétés de type AttributXXX dans les variables
    //de type Description de variable
     
    defClasse est un Définition
    dvMembre est Description de Variable
     
    defClasse=RécupèreDéfinition(objet)
    POUR TOUT dvMembre DE defClasse..Variable
    	SI dvMembre..AttributCléUnique ALORS
    		RENVOYER dvMembre..Nom
    	FIN
    FIN
     
    //Code pour version <= WD28, on est obligé de passer le nom "en dur"
    RENVOYER "m_pkClient"
     
    FONCTION p_ValIDClasse() : entier sur 8
    RENVOYER {ChaîneConstruit("p_pclTravail:%1",:p_NomIDClasse),indVariable}
    Getter de CGénérique
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    FONCTION p_NomIDClasse() : chaîne
    RENVOYER :m_pclTravail:p_NomIDClasse
     
    FONCTION PUBLIQUE p_NomPK() : chaine
    RENVOYER :m_pclTravail:p_NomPK
     
    FONCTION PUBLIQUE p_NomTable() : chaîne
    RENVOYER :m_pclTravail:p_NomTable
     
    FONCTION p_ValIDClasse() : entier sur 8
    RENVOYER {ChaîneConstruit("p_pclTravail:%1",:p_NomIDClasse),indVariable}
    Passons maintenant aux méthodes de CGénérique
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    PROCEDURE VIRTUELLE CAjoute()
    MémoireVersFichier(:p_pclTravail,:p_pclTravail:p_NomTable)
    HAjoute(:p_pclTravail:p_NomTable)
    //Les PK n'apparaissent pas dans l'occurrence, il faut les récupérer
    FichierVersMémoire(:p_pclTravail,:p_pclTravail:p_NomTable)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    PROCEDURE VIRTUELLE CLit(pkIDClasse est entier sur 8)
    HLitRecherchePremier(:p_NomTable,:p_NomPK,pkIDClasse)
    FichierVersMémoire(pclMaClasse,:p_NomTable)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    PROCÉDURE VIRTUELLE CModifie()
    SI :p_ValIDClasse=0 ALORS	//On ne peut pas modifier un enregistrement qui n'existe pas
    	SI :p_pclTravail<>Null ALORS
    		:p_pclTravail:CAjoute()
    	SINON
    		objet:CAjoute()        //Cas d'une utilisation "directe" i.e. avec un objet implémenté directement depuis une classe fille
    	FIN
    FIN
    HLitRecherchePremier(:p_NomTable,:p_NomPK,:p_ValIDClasse)
    HModifie(:p_NomTable)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    PROCÉDURE VIRTUELLE CSupprime(pkIDClasse est entier sur 8)
    HLitRecherchePremier(:p_NomTable,:p_NomPK,pkIDClasse)
    HSupprime(:p_NomTable)
     
    //Surcharge 1
    PROCÉDURE VIRTUELLE CSupprime()
    :CSupprime(:p_ValIDClasse)

  5. #5
    Membre chevronné Avatar de wd_newbie
    Homme Profil pro
    Développeur
    Inscrit en
    Mars 2007
    Messages
    755
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Développeur
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2007
    Messages : 755
    Par défaut
    ... Voroltinquo ... toujours aussi efficace !

    Je pense que je vais passer un moment a tout comprendre dans le détail, mais j'ai de quoi m'occuper un moment !!

    Un tout grand merci !

  6. #6
    Membre très actif
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Octobre 2013
    Messages
    387
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Maroc

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Octobre 2013
    Messages : 387
    Par défaut
    Bonjour

    Voir aussi l'exemple MVP de pcsoft

  7. #7
    Membre chevronné Avatar de wd_newbie
    Homme Profil pro
    Développeur
    Inscrit en
    Mars 2007
    Messages
    755
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Développeur
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2007
    Messages : 755
    Par défaut
    Bon ... j'ai passé un peu de temps sur le code et tenté de le mettre "à ma sauce", histoire de ne pas bêtement copier et d'essayer de comprendre ...


    Pour l'instant je teste juste la fonction "Lire()" du CRUD histoire de comprendre et des questions me viennent :

    - pourquoi un constructeur avec une surcharge nomClasse + nID en plus de nomClasse alors qu'il y a une méthode Lire(nID) qui fait la même chose ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    PROCÉDURE Constructeur(sNomClasse est une chaîne)
    :m_pclTravail = allouer un sNomClasse
     
    PROCÉDURE Constructeur(sNomClasse est une chaîne, nID est un entier sur 8 octets) 
    :m_pclTravail = allouer un sNomClasse
    HLitRecherchePremier(:p_NomFichier(),:p_NomID(), nID)
    FichierVersMémoire(:m_pclTravail,:p_NomFichier())
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    PROCÉDURE VIRTUELLE Lire(nID est un entier sur 8 octets)
     
    HLitRecherchePremier(:p_NomFichier(),:p_NomID(), nID)
    FichierVersMémoire(:m_pclTravail,:p_NomFichier())

    En utilisant soit la fonction Lire() ou le constructeur j'ai bien un objet :m_pclTravail qui est instancié avec les membres mappés :

    Nom : POO_1.png
Affichages : 1143
Taille : 11,9 Ko

    C'est un bon début, mais je n'ai pas compris comment lier mon objet :m_pclTravail à mes champs pour effectuer un SourceVersEcran()

    Ici mon objet est gclTest (ma classe générique s'appelle CCrud) , et je ne peut accéder aux membres

    Nom : POO_2.png
Affichages : 1139
Taille : 12,8 Ko

    Comment récupérer les infos de mon objet ?

    passer par un objet intermédiaire ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    gclTest est un CCrud("MClients")
    gclTest.Lire(4)
     
    clTemp est un objet dynamique 
     
    clTemp  = gclTest.p_pclTravail
     
    Trace(clTemp.m_sNom)

  8. #8
    Expert confirmé
    Avatar de Voroltinquo
    Homme Profil pro
    Chef de projet en SSII
    Inscrit en
    Juin 2017
    Messages
    2 933
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 59
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Chef de projet en SSII

    Informations forums :
    Inscription : Juin 2017
    Messages : 2 933
    Billets dans le blog
    1
    Par défaut
    En ce qui concerne le constructeur, c'est une vieille habitude. J'aime bien avoir accès à un objet "renseigné" dès son allocation.
    Cela est précisé dans les commentaire de l'interface.

    On ne peut pas accéder aux membres (donc pas aux getters) d'un d'une variable de type objet dynamique, on le voit lors de la complétion.
    Pour l'affichage, le plus simple est de passer par une déclaration "directe" e.g.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    clMonClient est CClient
    J'ai codé ce type d'accès dans CModifie (utilisation de "objet")

    Soit se créer des méthodes dans une nouvelle interface afin de simuler l'affectation d'un getter/setter à un champ (SourceVersEcran/EcranVersSource)
    Un truc du style :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    PROCÉDURE ChampVersMembre(chOrig est Champ,pMembre)
    pMembre=chOrig..Valeur
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    PROCÉDURE MembreVersChamp(chDest est Champ,pMembre)
    chDest=pMembre

  9. #9
    Membre chevronné Avatar de wd_newbie
    Homme Profil pro
    Développeur
    Inscrit en
    Mars 2007
    Messages
    755
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Développeur
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2007
    Messages : 755
    Par défaut
    Bon je crois que j'ai enfin réussi a faire quelque chose qui tourne ... voir ci-dessous en fin de post.

    J'ai quand même quelques questions :

    1 - je dois renseigner les variables dans mon constructeur de la classe fille

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    :m_sFichier = "Clients"
    ça ne fonctionne pas quand je l'instancie dans la partie "Classe "

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    m_sFichier 		est une chaîne = "Clients"       // nom du fichier de données (table)
    ça m'aurait semblé plus propre ...


    2 - j'ai supprimer les attributs VIRTUELLE dans les méthode de la classe mère et ça fonctionne toujours.

    LA seule infos que j'ai réussi à glaner, cest :

    VIRTUELLE indique que si cette méthode est redéfinie dans une classe dérivée, c'est la méthode de la classe dérivée qui sera appelée même depuis cette classe
    Si elle est dans la classe mère elle n'est pas dérivée ... si ? et si elle n'est pas pas définie dans la classe fille ... elle n'est pas redéfinie ? (... bref j'ai rien compris ...)

    3 - Je ne suis pas trop en dehors des clous ?


    Mes "essais" pour la classe "générique" :

    Pour la classe avec le mapping

    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
     
     
    MClients est une Classe <MAPPING=Clients>
    hérite de CCrud
     
    	// Le code se trouvant entre <MAPPING> et <FIN> est généré automatiquement.
    	// Il sera effacé et recréé entièrement à chaque génération depuis l'analyse.
    	<MAPPING>
    	m_nCL_ID		        est un entier sur 8 octets	        <MAPPING=CL_ID, clé unique>
    	m_sCL_Nom		est une chaîne ANSI			<MAPPING=CL_Nom>
    	m_sCL_Prenom	        est une chaîne ANSI			<MAPPING=CL_Prenom>
    	<FIN>
     
    	PRIVÉ
    		m_sFichier 		est une chaîne       // nom du fichier de données (table)
    		m_sCle			est une chaîne	   // cle unique :  ID 
    		m_sClasse		est une chaîne 	  //  nom de la classe  
     
     
    FIN
     
    PROCÉDURE Constructeur()
     
     
    :m_sFichier = "Clients"
    :m_sCle = "CL_ID"
    :m_sClasse = "MClients"
    Ancêtre:Constructeur (:m_sFichier,:m_sCle,:m_sClasse)

    et pour la classe générique

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
     
     
    CCrud est une Classe
     
    	PRIVÉ
    	//m_pclclDatas est un objet dynamique
     
     
    	m_sFichierMappe est une chaîne
    	m_SCleMappe est une chaîne
    	m_sClasse est une chaîne 
     
     
    FIN
     
    PROCÉDURE Constructeur(sfichier, sCle, sClasse)
     
    	:m_sFichierMappe = sfichier
    	:m_SCleMappe = sCle
    	:m_sClasse = sClasse
     
     
     
    PROCÉDURE Lire(nID)
     
    HLitRecherche(:m_sFichierMappe,:m_SCleMappe,nID)
    FichierVersMémoire(objet,:m_sFichierMappe)
     
     
    PROCÉDURE  Sauvegarder()
     
     
     
    // si on est en mode ajout ou modification 
    SI {":m_n" + :m_SCleMappe,indVariable}= Null ALORS
    	HRAZ(:m_sFichierMappe) 
    	MémoireVersFichier(objet,:m_sFichierMappe)
    SINON 
     
     
    	HLitRecherchePremier(:m_sFichierMappe,:m_SCleMappe,{":m_n" + :m_SCleMappe}) 
    	SI HTrouve(:m_sFichierMappe)ALORS 
    		MémoireVersFichier(objet, :m_sFichierMappe)
    	SINON 
    		ErreurPropage("Client " + {:m_SCleMappe}+ " non trouvé dans la base !") 
    		HFerme(:m_sFichierMappe)
    		RENVOYER Faux 
    	FIN
    FIN
     
    // -- on enregistre --
    HEnregistre(:m_sFichierMappe) 
     
    {":m_n" + :m_SCleMappe,indVariable}= {:m_sFichierMappe + "." + :m_SCleMappe}
    HFerme(:m_sFichierMappe)
    RENVOYER Vrai  
     
     
     
    CAS ERREUR:
    ErreurPropage()
    RENVOYER Faux
    CAS EXCEPTION:
    ExceptionPropage()
    RENVOYER Faux
     
     
    PROCÉDURE   Supprimer()
     
    HLitRecherchePremier(:m_sFichierMappe,:m_SCleMappe,{":m_n" + :m_SCleMappe}) 
    SI HTrouve() ALORS 
    	HSupprime(:m_sFichierMappe) 
    	RENVOYER Vrai 
    FIN
     
    RENVOYER Faux 
     
     
    CAS ERREUR:
    ErreurPropage()
    RENVOYER Faux
    CAS EXCEPTION:
    ExceptionPropage()
    RENVOYER Faux

  10. #10
    Expert confirmé
    Avatar de Voroltinquo
    Homme Profil pro
    Chef de projet en SSII
    Inscrit en
    Juin 2017
    Messages
    2 933
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 59
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Chef de projet en SSII

    Informations forums :
    Inscription : Juin 2017
    Messages : 2 933
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par wd_newbie Voir le message
    on doit créer des getter/ setter pour chaque membre mappé
    Privé est l'accès par défaut d'un membre donc les getter/setter s'imposent. Mais on n'est pas obligé de créer les deux.
    Si on veut interdire l'accès à un membre en écriture, (e.g. m_nCL_ID) on ne crée pas de setter
    Citation Envoyé par wd_newbie Voir le message
    Je n'ai pas trouvé comment faire pour, depuis une classe mère, accéder aux infos de la classe fille. De cette façon, il serait possible de "déporter" les méthodes dans la classe mère.
    L'objet fils, c'est m_pclTravail.
    Par contre, une fois un objet instancié, on ne se soucie plus de quoi il hérite. C'est avec cet objet qu'on travaille. Un peut comme avec une requête, on se fiche de la table dont provient la colonne, on accède à cette colonne via la requête.

  11. #11
    Membre chevronné Avatar de wd_newbie
    Homme Profil pro
    Développeur
    Inscrit en
    Mars 2007
    Messages
    755
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Développeur
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2007
    Messages : 755
    Par défaut
    Zut ... je n'avais pas vu que tu avais répondu en dessous... visiblement je ne suis pas le seul a bosser le samedi soir

    ... j'ai modifié mon post précédent avec mes dernières élucubratiosn ... heu ... trouvailles ...

    ça semble fonctionner pas trop mal, la seule chose me pose encore un soucis, c'est que je n'arrive pas à rendre la méthode "Lister()" générique, quitte à la surcharger pour les listes qui demandes des filtres

    C'est le

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    taclListeEnr  est un tableau de :m_sNomClasse
    qui embête est le :m_sNomClasse , on ne peut instancier sans passer par un objet dynamique , même en utilisant les indirections.

    et avec un oblet dynamique ... non plus ...

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    oObj est un objet dynamique
    oObj <- allouer un :m_sClasse
    pourtant dans ton exemple, dans le constructeur, ça fonctionne, mais là je suis dans une procédure globale je ne peux donc pas accéder aux membres.

    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
    PROCÉDURE PUBLIQUE GLOBALE Lister()
    
    taclListeEnr  est un tableau de :m_sNomClasse
    
    rs est une Requête SQL = 
    [
    	SELECT * FROM Options
    ]
    
    
    SI PAS HExécuteRequêteSQL(rs, hRequêteDéfaut) ALORS 
    	ErreurPropage(HErreurInfo())
    SINON 
    	FichierVersTableau(taclListeEnr  ,rs) 
    FIN
    
    RENVOYER taclListeEnr  
    
    
    
    CAS ERREUR:
    ErreurPropage()
    RENVOYER Faux
    CAS EXCEPTION:
    ExceptionPropage()
    RENVOYER Faux

  12. #12
    Expert confirmé
    Avatar de Voroltinquo
    Homme Profil pro
    Chef de projet en SSII
    Inscrit en
    Juin 2017
    Messages
    2 933
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 59
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Chef de projet en SSII

    Informations forums :
    Inscription : Juin 2017
    Messages : 2 933
    Billets dans le blog
    1
    Par défaut
    Si l'indirection ne peut plus rien pour vous, il vous reste un recours, un seul : la compilation dynamique
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    CListeGenerique est une Classe
    PRIVE
    	m_ptabGénérique est tableau
            m_clInfo est CGénérique	//Pour récupération du nom de la table "Source"
    FIN
    Surcharge du constructeur
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    PROCÉDURE Constructeur(saNomClasse est chaîne)
    m_clInfo = allouer un CGénérique(saNomClasse)
     
    DéclareTableau(saNomClasse)
    FichierVersTableau(:m_ptabGénérique,:NomTable)
    Avec
    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
    PROCÉDURE PRIVÉE DéclareTableau(saNomClasse est chaîne)
    saCode est une chaîne
    saResCompil est chaîne
     
    saCode=[
    	tabObjet est tableau de %1
     
    	RENVOYER tabObjet
    ]
    saCode=ChaîneConstruit(saCode,saNomClasse)
     
    saResCompil=Compile("DéclarationTableau",saCode)
    SELON saResCompil
    	CAS "" : :m_ptabGénérique=ExécuteTraitement("DéclarationTableau", trtProcédure)
    	CAS "ERR" : ErreurConstruit( "Compilation impossible.%1%2",CRLF,ErreurInfo())
            AUTRE CAS : Erreur(saResCompil)
    FIN
    Avec le getter
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    FONCTION PUBLIQUE NomTable()
     
    RENVOYER m_clInfo:p_NomTable
    Concernant les procédures virtuelle elles sont définies dans les interface donc ce sont des procédures dérivées.

  13. #13
    Membre chevronné Avatar de wd_newbie
    Homme Profil pro
    Développeur
    Inscrit en
    Mars 2007
    Messages
    755
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Développeur
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2007
    Messages : 755
    Par défaut
    Bon je me suis pris un peu la tête avec ton code ... j'ai une erreur "ligne incomplète" avec la déclaration :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    m_ptabGénérique est tableau
    Il semble attendre le type de tableau (ma version 23 ? )

    Mais en réfléchissant un peu (...si...si ...) , du moment que la fonction doit me retourner un "tableau de <objet>" , et que je dois de toute façon le déclarer dans mon code appelant :

    SI je me base sur les exemples trouvés sur le web :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
        tabTaclClients est un tableau de MClients 
        tabTaclClients  = MClient::Lister()
    Si je passe mon tableau en paramètre par référence a ma méthode de classe, je n'ai pas besoin de le redéfinir dans la méthode :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
        tabTaclClients est un tableau de MClients 
        gclClient.Lister(tabTaclClients)
    J'ai supprimé la portée globale de la méthode pour avoir accès aux infos du fichier mappé

    ... et ça marche, en vérifiant les objets je n'ai rien vu d'horrible, la méthode renvoie simplement mon tableau basée sur une requête dynamique.

    c'est pas trop en dehors des clous ?

  14. #14
    Expert confirmé
    Avatar de Voroltinquo
    Homme Profil pro
    Chef de projet en SSII
    Inscrit en
    Juin 2017
    Messages
    2 933
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 59
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Chef de projet en SSII

    Informations forums :
    Inscription : Juin 2017
    Messages : 2 933
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par wd_newbie Voir le message
    Il semble attendre le type de tableau (ma version 23 ? )
    C'est normal quelle que soit la version. Lorsque tu veux utiliser un tableau non typé, il faut utiliser un tableau dynamique
    Citation Envoyé par wd_newbie Voir le message
    ... et ça marche, en vérifiant les objets je n'ai rien vu d'horrible.
    Oh que si, ce n'est simplement pas objet (de mon point de vue) car la règle d'encapsulation n'est pas respectée.
    Avec ta méthode l'utilisateur de MClient peut par exemple avoir accès aux données bancaires d'un autre client une fois son client instancié.
    Qui plus est, les traitement que tu vas faire sur une liste de clients ne sont pas les même que ceux que tu vas faire sur un client.

    Il faut travailler avec 2 classes une classe MClient et une classe CListeClient
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    CListeClient est classe
    PRIVE
         m_tabClient est tableau de MClient
    On a alors accès à un client via :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    clMonClient est MClient
    clMaliste est CListeClient
     
    clMonClient=clMaListe:p_tabClient[12]
    ou alors :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    clMonClient est MClient
    clMaliste est CListeClient
     
    clMonClient=clMaListe:CLit(12)
    Avec
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    FONCTION CLit(nIndice est entier) : MClient
    RENVOYER :m_tabClient[nIndice]
    Je ne comprend pas ta remarque
    J'ai supprimé la portée globale de la méthode pour avoir accès aux infos du fichier mappé
    1-Si rien n'est précisé, la Procédure/Fonction/Méthode est globale
    2-Qu'est ce qui empêche d'avoir accès aux infos du fichier mappé ?

  15. #15
    Expert confirmé
    Avatar de Voroltinquo
    Homme Profil pro
    Chef de projet en SSII
    Inscrit en
    Juin 2017
    Messages
    2 933
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 59
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Chef de projet en SSII

    Informations forums :
    Inscription : Juin 2017
    Messages : 2 933
    Billets dans le blog
    1
    Par défaut Une petite histoire pour illustrer mes propos
    Maurice, un commercial, a un portefeuille de clients. Son CA est en baisse, il faudrait qu'il prospecte, mais c'est l'hiver, les routes sont glissantes et le soir, après ses 10 Ricards au Balto, c'est pire.
    Un jour, à la machine à café, il entend 2 employés du Service informatique discuter:
    -Ce soir vacances, j'ai du coder la nouvelle gestion des portefeuilles avec le cul, ça tourne mais bon... Je verrai ça à mon retour.
    Voici un extrait de la classe Client
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    CClientNonSécurisé est une Classe
    <MAPPING>
    	m_pkClient		est un entier sur 8	<MAPPING=PK_Client, clé unique>
    	m_saNoClient		est une chaîne		<MAPPING=AK_NoClient>
    	m_pkCommercial	est entier sur 8   	<MAPPING=FK_Commercial>
    	m_saNomClient		est une chaîne		<MAPPING=NDX_NomClient>
    	m_saVille			est chaîne 		<MAPPING=NDX_Ville>
    	m_saEtc_Client		est une chaîne		<MAPPING=Etc_Client>
    	m_saTypeClient		est une chaîne		<MAPPING=NDX_TypeClient>
    <FIN>
     
    FIN
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    FONCTION ListeClient() : tableau de CClientNonSécurisé
    tabRes est tableau de CClientNonSécurisé
     
    FichierVersTableau(tabRes,Client)
     
    RENVOYER tabRes

    Voici le code qu'a créé Maurice:
    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
     
    clUnClientMaurice est CClientNonSécurisé
    tabClients est un tableau de CClientNonSécurisé
    tabClientsTotoVille est tableau de CClientNonSécurisé
    pkMaurice est entier sur 8
     
    clUnClientMaurice=allouer un CClientNonSécurisé(2) //Dans la réalité Maurice à récupéré un des client de sa liste
    tabClients=clUnClientMaurice:ListeClient()
    //Maurice dispose de tout les clients de l'entreprise
    //Totoville est proche du secteur de Maurice, il va rechercher les clients de Totoville
    tabClientsTotoVille=ChercherClientVille(tabClients,"Totoville")
    //Tout les membres sont publics, quelle aubaine pour Maurice
    pkMaurice=clUnClientMaurice:m_pkCommercial
    ChangeCommercial(tabClientsTotoVille,pkMaurice)
    //En 10 min Maurice a récupéré les clients existant à Totoville.
    //Il suffit de les contacter et de leur dire que leur nouveau commercial c'est lui
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    PROCÉDURE ChercherClientVille(tabClients est tableau de CClientNonSécurisé,saVille est chaîne) :tableau de CClientNonSécurisé
    tabRes est tableau de CClientNonSécurisé
    nRésultatRecherche est un entier
     
    nRésultatRecherche=TableauCherche(tabClients,tcLinéaire,"m_saVille",saVille)
    TANTQUE nRésultatRecherche<>-1
    	TableauAjoute(tabRes,tabClients[nRésultatRecherche])
    	nRésultatRecherche=TableauCherche(tabClients,tcLinéaire,"m_saVille",saVille,nRésultatRecherche+1)
    FIN
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    PROCÉDURE ChangeCommercial(tabClientsTotoVille est tableau de CClientNonSécurisé,pkCommercial est entier sur 8)
    nIndice est un entier
     
    POUR nIndice = 1 _À_ tabClientsTotoVille..Occurrence
            HLitRecherchePremier(Client,PK_Client,tabClientsTotoVille[nIndice]:m_pkClient)
    	tabClientsTotoVille[nIndice]:m_pkCommercial=pkCommercial
    	MémoireVersFichier(tabClientsTotoVille[nIndice],Client)
    	HModifie(Client)
    FIN
    Voilà ce qui se passe lorsque les règles d'encapsulation ne sont pas respectées.
    La POO est une manière de coder différente du procédural, au même titre que SQL ou la programmation déclarative (cf PROLOG)

  16. #16
    Membre chevronné Avatar de wd_newbie
    Homme Profil pro
    Développeur
    Inscrit en
    Mars 2007
    Messages
    755
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Développeur
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2007
    Messages : 755
    Par défaut
    Il file du mauvais coton ce Maurice ... je vous l'dis pas

    Oui je comprends sur le principe pour l'encapsulation, mais dans la pratique ça implique que Maurice, commercial, puisse avoir accès au code du soft au logiciel de dev et tout et tout et dans ce cas il pourrait utiliser la classe ClisteClients qui renverrait quand même la liste des clients.

    Ensuite libre a lui de flinguer ce qu'il veut ... non ?
    Ou alors je passe complètement à côté de l'exemple

  17. #17
    Expert confirmé
    Avatar de Voroltinquo
    Homme Profil pro
    Chef de projet en SSII
    Inscrit en
    Juin 2017
    Messages
    2 933
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 59
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Chef de projet en SSII

    Informations forums :
    Inscription : Juin 2017
    Messages : 2 933
    Billets dans le blog
    1
    Par défaut
    Il n'a pas les droits sur CListeClients il n'est utilisateur que de CClientDangereux pour accéder à ses clients (en théorie)
    Ou alors je passe complétement à côté de l'exemple
    Plus ou moins. Cet exemple servait à illustrer le fait que l'utilisateur d'une classe ne doit avoir accès qu'à ce qu'on veut bien lui accorder via les méthodes et les getter/setter et en aucun cas à autre chose.
    Dans notre cas, le fait d'avoir accès à un client via un autre client est un biais.
    De là à écrire que Maurice est un grand biaiseur, il n'y a qu'un pas
    Je te renvoie à la lecture d'un extrait de" Introduction à la programmation orientée objet (POO) en C#" qui reformule mon explication.

  18. #18
    Expert confirmé
    Avatar de frenchsting
    Homme Profil pro
    multitâches-multifonctions
    Inscrit en
    Juin 2003
    Messages
    5 518
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Meurthe et Moselle (Lorraine)

    Informations professionnelles :
    Activité : multitâches-multifonctions
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2003
    Messages : 5 518
    Par défaut
    Citation Envoyé par Voroltinquo Voir le message
    De là à écrire que Maurice est un grand biaiseur, il n'y a qu'un pas
    Il fallait l'oser celle là => Je plussoie...

    Nan, je déconne, je plussoie pour l'explication
    ...et je me dis que j'ai de la chance de ne pas avoir à faire de l'objet
    ...je me contente de décrypter le code C# des anciens collègues, et je me dis : Pourquoi tant de haine ???????????????????

  19. #19
    Membre chevronné Avatar de wd_newbie
    Homme Profil pro
    Développeur
    Inscrit en
    Mars 2007
    Messages
    755
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Développeur
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2007
    Messages : 755
    Par défaut
    Je vais passer une classe pour lister les clients, même si avoir "une classe pour les dominer gérer tous" me plaisait bien

    Je vais me pencher sur le lien proposé.

    Dans tous les cas un très grand merci pour ton aide !


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

Discussions similaires

  1. [POO] class abstraite CRUD & DAO
    Par mazenovi dans le forum Langage
    Réponses: 2
    Dernier message: 13/04/2006, 19h45
  2. [Language][POO]classe interface
    Par Samanta dans le forum Langage
    Réponses: 9
    Dernier message: 21/06/2005, 15h32
  3. Réponses: 3
    Dernier message: 19/05/2005, 10h46
  4. [POO] Class Défilementa automatique d'images avec animation
    Par rakoto.n dans le forum Général JavaScript
    Réponses: 9
    Dernier message: 14/01/2005, 18h21
  5. classe date générique ?
    Par lili_bzh dans le forum Décisions SGBD
    Réponses: 1
    Dernier message: 07/09/2004, 10h59

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