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] Mapping, Databinding, MVP architecture - Questions


Sujet :

WinDev

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Janvier 2020
    Messages
    66
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France, Aisne (Picardie)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Janvier 2020
    Messages : 66
    Par défaut [POO] Mapping, Databinding, MVP architecture - Questions
    Bonsoir,

    Depuis quelques semaines je m'intéresse à la POO afin de structurer mon projet, séparer les couches UI/Métier, etc.

    Selon ma logique et après pas mal de recherche, je souhaiterais partir sur l'architecture suivante : Fenêtre <-> Classe Contrôleur/Presentation propre à ma fenêtre <-> Classes modèles mappées sur mes fichiers de données <-> BDD

    Question préalable : Est-ce bien une architecture MVP ? J'ai analysé en profondeur les deux exemples fournis par PCSOFT MVP1/MVP2. Cela ressemble à ça, sauf qu'eux passent les couches présentations en paramètre dans les fenêtres et travaillent pratiquement qu'en mémoire, pas de rafraîchissement de tables etc. Moi je souhaite passer les ID dans mes fenêtres afin d'actualiser les données, recharger mes tables afin d'avoir des données toujours à jour (dans le cas où d'autres utilisateurs auraient modifiés des données entre temps etc.)


    Cas concret : (J'ai pris cet exemple là afin d'avoir un exemple concret, je réutiliserais le même principe pour mes autres fenêtres)

    J'ai une table société, une table société_probleme, une table probleme_contact et une table contact. Je m'intéresse à la partie Societe_Probleme, Probleme_Contact. Pour un problème donné, je peux associer plusieurs contacts à ce problème. J'ai donc :

    Nom : Probleme.jpg
Affichages : 4064
Taille : 172,7 Ko


    J'ai généré mes classes MProbleme, MProbleme_Contact et MContact

    Classe MProbleme :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    MProbleme est une Classe <MAPPING=Societe_Probleme>
    hérite de MBase
    
    <MAPPING>
    m_nPBid			est un entier sur 8 octets				<MAPPING=DRPBid>
    m_nPBcode			est un entier sans signe sur 4 octets	<MAPPING=DRPBcode, clé unique>
    m_nPBnom est une chaine <MAPPING=PBnom>
    m_sPBdescript		est une chaîne ANSI						<MAPPING=DRPBdescript>
    m_dPBdate			est une Date							<MAPPING=DRPBdate>
    <FIN>
    	
    m_tabProblemeContact est un tableau de MProbleme_Contact dynamique //Dois-je déclarer ici le tableau ? (Plusieurs contacts sont associés au problème)
    
    FIN
    Possède la méthode ChargeElement pour charger le problème, les méthodes d'enregistrement etc.


    Classe MProbleme_Contact :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    MProbleme_Contact est une Classe <MAPPING=Probleme_Contact>
    hérite de MBase
    <MAPPING>
    m_nPBCONTid est un entier <MAPPING=PBCONTid, clé unique>
    m_nPBcode		est un entier   <MAPPING=PBcode>
    m_nCONTcode		est un entier   <MAPPING=CONTcode>
    m_sPBCONTcom 	est une chaine <MAPPING=PBCONTcom>
    <FIN>
     
    m_pclContact est un MContact dynamique
    FIN
    Possède la méthode : tabCharge qui renvoie un tableau de contact pour un problème donné


    J'ai également créé une classe PFicheProbleme qui gère les actions des utilisateurs sur la fenêtre, initialise les données en appelant les méthodes des classes MProbleme et MProbleme_Contact etc.

    Classe Controleur/Présentation PFicheProbleme :
    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
    PFicheProbleme est une Classe	
    	m_pclProbleme				est un MProbleme dynamique <associé>	//classe Problème, possède un tuple tableau contact
    	m_pclProblemeContact		est un MProbleme_Contact dynamique			//Élément courant du tableau Contact
    FIN
    
    Constructeur(PBcode)
    m_pclProbleme <- allouer un MProbleme(PBcode)
    m_pclProblemeContact <- allouer un MProblemeContact(PBcode)
    
    Méthode ChargeProbleme // qui va appeler la méthode de la classe MProbleme :
    Si m_pclProbleme.bHChargeElement()=faux alors
    erreurdéclenche(2,...)
    renvoyer faux
    fin
    demandemiseajourui()
    renvoyer vrai
    
    Méthode ChargeTableProblemeContact // qui va remplir mon tableau de mon objet à partir de la méthode de la classe MProblemeContact
    m_pclProbleme.m_tabProblemeContact = m_pclProblemeContact.tabCharge()
    demandemiseajourui("CONTACT")

    Maintenant mes questions concernant tout ça :

    Q1) Déjà est-ce que la façon de faire est bonne, propre ?

    Q2) Dois-je déclarer le tableau : m_tabProblemeContact est un tableau de MProbleme_Contact dynamique directement dans ma classe MProbleme comme j'ai fait OU alors le déclarer dans ma classe présentation PFicheProbleme et le remplir indépendamment de mon objet Probleme ? (Ligne en rouge dans mon exemple)

    Q3) Si je conserve "m_tabProblemeContact est un tableau de MProbleme_Contact dynamique" dans ma classe MProbleme. Est-ce que je dois créer dans ma classe MProbleme une méthode "ChargeTableauProblemeContact" qui va exécuter la méthode TabCharge (Renvoie un tableau) de ma classe MProbleme_Contact afin de remplir le tableau ? Ou alors j'appelle directement ma méthode TabCharge depuis ma classe Présentation PFicheProbleme comme j'ai fait dans mon exemple ci-dessus (Code en vert)

    Q4) Dans le cas concret que j'ai exposé ci-dessus, si je veux ajouter une ligne à mon tableau m_tabProblemeContact de ma classe MProbleme (tableau de MProblemeContact) , où dois-je écrire cette méthode ?
    - Dans ma classe Présentation ?
    - Dans ma classe MProblemeContact (où j'ai la méthode pour me renvoyer un tableau) en passant mon tableau en paramètre de ma méthode ? Dans ce cas, je dois appeler la méthode à partir de ma classe présentation ? Ou je dois dans ma classe MProbleme écrire aussi une méthode "Ajouter Ligne" qui va chercher la méthode dans MProblemeContact afin d'ajouter la ligne à son propre tableau membre ?
    - Ou alors créer une classe indépendante "tableau" de Probleme_Contact :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    MTableauProbleme_Contact est une classe
    m_tabProblemeContact est un tableau de MProbleme_Contact dynamique
    avec les méthodes de chargement, d'ajout, modification, et suppression de ligne
    et ainsi remplacer dans ma classe MProbleme : "m_tabProblemeContact est un tableau de MProbleme_Contact dynamique" PAR "m_pclProblemeContact est un MTableauProbleme_Contact dynamique" et utiliser directement les méthodes de cette classe pour charger mon tableau, ajouter ligne etc


    J'espère m'être fait comprendre, pas facile à l'écrit


    Merci d'avance à ceux qui prendront le temps de m'aider ou me donner leur avis

    Bonne soirée,

    Esteban

  2. #2
    Membre expérimenté

    Homme Profil pro
    Sans
    Inscrit en
    Mars 2018
    Messages
    153
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Sans

    Informations forums :
    Inscription : Mars 2018
    Messages : 153
    Billets dans le blog
    1
    Par défaut
    Bonjour Djsven,

    Je vais tenter de répondre à tes interrogations même si mon expérience avec Windev ne remonte pas à plus de 8 à 10 mois et que certainement des personnes plus expérimentées pourr-aient-ont apporter un avis plus professionnel.

    Citation Envoyé par Djsven Voir le message
    Bonsoir,

    Depuis quelques semaines je m'intéresse à la POO afin de structurer mon projet, séparer les couches UI/Métier, etc.

    Selon ma logique et après pas mal de recherche, je souhaiterais partir sur l'architecture suivante : Fenêtre <-> Classe Contrôleur/Presentation propre à ma fenêtre <-> Classes modèles mappées sur mes fichiers de données <-> BDD

    Question préalable : Est-ce bien une architecture MVP ? J'ai analysé en profondeur les deux exemples fournis par PCSOFT MVP1/MVP2. Cela ressemble à ça, sauf qu'eux passent les couches présentations en paramètre dans les fenêtres et travaillent pratiquement qu'en mémoire, pas de rafraîchissement de tables etc. Moi je souhaite passer les ID dans mes fenêtres afin d'actualiser les données, recharger mes tables afin d'avoir des données toujours à jour (dans le cas où d'autres utilisateurs auraient modifiés des données entre temps etc.)

    ...
    Tu n'es pas obligé de passer la classe de présentation en paramètre à ta fenêtre. Il suffit de déclarer dans la partie déclarations globales :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
     goPresentation est une classeDePresentationDeMaFenetre dynamique <présentation> <- allouer une classeDePresentationDeMaFenetre

    Citation Envoyé par Djsven Voir le message
    ...

    Maintenant mes questions concernant tout ça :

    Q1) Déjà est-ce que la façon de faire est bonne, propre ?
    C'est un bon début que de vouloir mettre en place un développement basé sur le pattern MVP. D'après la doc PCSoft : https://doc.pcsoft.fr/fr-FR/?1000021496, ton architecture correspond, peu ou prou, à une architecture MVP.

    Cependant, AMHA, tes "classes modèles mappées sur mes fichiers de données" doivent rester atomiques. J'entends par là qu'elles ne doivent représenter qu'un seul enregistrement de ta table (ton fichier en langage windev) et grâce à l'héritage de la classe MBase, être manipulée avec les méthodes Charger(), bEnregistrer() et Supprimer().

    J'intercalerai, entre ta classe "présentation" et ta classe "modèle mappées sur mes fichiers de données" une couche, que l'on pourrait appeler "façade" supplémentaire qui se chargerait de :
    - Manipuler une ou plusieurs classes mappées aux fichiers. La logique métier de ton application.
    - Proposer à ta couche présentation une API simple permettant de s'affranchir de la complexité des relations existantes entre les différentes classes de mapping


    Citation Envoyé par Djsven Voir le message

    Q2) Dois-je déclarer le tableau : m_tabProblemeContact est un tableau de MProbleme_Contact dynamique directement dans ma classe MProbleme comme j'ai fait OU alors le déclarer dans ma classe présentation PFicheProbleme et le remplir indépendamment de mon objet Probleme ? (Ligne en rouge dans mon exemple)

    Q3) Si je conserve "m_tabProblemeContact est un tableau de MProbleme_Contact dynamique" dans ma classe MProbleme. Est-ce que je dois créer dans ma classe MProbleme une méthode "ChargeTableauProblemeContact" qui va exécuter la méthode TabCharge (Renvoie un tableau) de ma classe MProbleme_Contact afin de remplir le tableau ? Ou alors j'appelle directement ma méthode TabCharge depuis ma classe Présentation PFicheProbleme comme j'ai fait dans mon exemple ci-dessus (Code en vert)
    Dans la classe "classeDePresentationDeMaFenetre ", je déclarerais une variable publique qui serait un tableau de MProblemeContact (ou peut-être même de cProblèmeContact :<= la façade) qui serait bindé à la table qui sert à l'affichage.

    Citation Envoyé par Djsven Voir le message
    Q4) Dans le cas concret que j'ai exposé ci-dessus, si je veux ajouter une ligne à mon tableau m_tabProblemeContact de ma classe MProbleme (tableau de MProblemeContact) , où dois-je écrire cette méthode ?
    - Dans ma classe Présentation ?
    - Dans ma classe MProblemeContact (où j'ai la méthode pour me renvoyer un tableau) en passant mon tableau en paramètre de ma méthode ? Dans ce cas, je dois appeler la méthode à partir de ma classe présentation ? Ou je dois dans ma classe MProbleme écrire aussi une méthode "Ajouter Ligne" qui va chercher la méthode dans MProblemeContact afin d'ajouter la ligne à son propre tableau membre ?
    - Ou alors créer une classe indépendante "tableau" de Probleme_Contact :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    MTableauProbleme_Contact est une classe
    m_tabProblemeContact est un tableau de MProbleme_Contact dynamique
    avec les méthodes de chargement, d'ajout, modification, et suppression de ligne
    et ainsi remplacer dans ma classe MProbleme : "m_tabProblemeContact est un tableau de MProbleme_Contact dynamique" PAR "m_pclProblemeContact est un MTableauProbleme_Contact dynamique" et utiliser directement les méthodes de cette classe pour charger mon tableau, ajouter ligne etc


    J'espère m'être fait comprendre, pas facile à l'écrit


    Merci d'avance à ceux qui prendront le temps de m'aider ou me donner leur avis

    Bonne soirée,

    Esteban
    Pour ajouter une ligne dans ton tableau, il te faut une autre fenêtre avec sa classe de présentation associée qui se chargerait de l'ajout.
    Pour supprimer une ligne dans ton tableau, il te faut une autre fenêtre avec sa classe de présentation associée qui se chargerait de la suppression.

    Je rajouterai que, à mon sens, l'attribut <associé> doit être à proscrire car il va à l'encontre de la notion d'encapsulation.

    hth,
    Padbrain.

  3. #3
    Membre confirmé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Janvier 2020
    Messages
    66
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France, Aisne (Picardie)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Janvier 2020
    Messages : 66
    Par défaut
    Salut Padbrain, merci d'avoir pris le temps de me répondre,

    Citation Envoyé par padbrain Voir le message
    J'intercalerai, entre ta classe "présentation" et ta classe "modèle mappées sur mes fichiers de données" une couche, que l'on pourrait appeler "façade" supplémentaire qui se chargerait de :
    - Manipuler une ou plusieurs classes mappées aux fichiers. La logique métier de ton application.
    - Proposer à ta couche présentation une API simple permettant de s'affranchir de la complexité des relations existantes entre les différentes classes de mapping
    Je voyais justement la classe "Présentation" comme la couche façade me permettant justement d'y faire mes traitements. Avant de penser à cette classe intermédiaire, je manipulais mes actions avec mes classes modèles dans des procédures locales/globales, c'est pour cela que je me suis dit que ça serait sans doute plus propre d'ajouter cette classe intermédiaire qui, selon les actions utilisateurs cotés UI, me permettrait de manipuler mes classes modèles. C'est pour cela aussi que je m'y perd un peu, à savoir si je dois plutôt écrire ma méthode coté classe modèle, ou plutôt coté classe intermédiaire "présentation". Je reprendrais dans la suite de mon message l'exemple de l'ajout d'une ligne à un tableau que j'ai récupéré à partir d'une méthode d'une classe.



    Citation Envoyé par padbrain Voir le message
    Dans la classe "classeDePresentationDeMaFenetre ", je déclarerais une variable publique qui serait un tableau de MProblemeContact (ou peut-être même de cProblèmeContact :<= la façade) qui serait bindé à la table qui sert à l'affichage.
    C'est ce que je faisais aussi, mais étant donné que justement cette variable tableau de MProbleme_Contact est liée à ma classe MProbleme (Un problème peut avoir un ou plusieurs contacts associés, donc mes contacts sont liés à un problème), n'est-ce pas plus propre de définir directement ma variable Tableau de MProbleme_Contact comme un membre de ma classe MProbleme ?

    Donc dans ma classe présentation, plutôt que déclarer ma variable tableau en plus de ma variable objet MProbleme, je déclarerais simplement la variable qui est un objet de MProbleme qui possèdes les membres mappés sur mon fichier d'analyse et qui possède également le tableau de ma classe MProbleme_Contact (Ce dernier sera databindé sur ma table visuelle coté UI). Et j'accéderais au tableau de contacts associés par MonObjProbleme.MontableauDeMProblemeContact ?



    Citation Envoyé par padbrain Voir le message
    Pour ajouter une ligne dans ton tableau, il te faut une autre fenêtre avec sa classe de présentation associée qui se chargerait de l'ajout.
    Pour supprimer une ligne dans ton tableau, il te faut une autre fenêtre avec sa classe de présentation associée qui se chargerait de la suppression.
    Pour les ajouts et suppressions de ligne, je parlais dans la variable publique de mon tableau d'objet, quand j'ai déjà ouvert la fiche pour ajouter et que je valide. 90% du temps après un ajout en bdd je recharge toute la table visuelle afin d'avoir des données à jour, dans ce cas pas de problème je rappelle simplement ma méthode tabCharge de ma classe correspondante. Mais pour certains cas, je dois simplement ajouter une ligne à ma table visuelle sans tout rafraichir (Équivalent d'un tableAjouteLigne()), donc ici un tableauajoute(Tableau mémoire, Objet mémoire) + un tableAffiche() vu que ma table visuelle est databindée sur ma variable tableau.


    Comme j'ai dit plus haut, je m'y perd pour savoir où je dois déclarer ma méthode pour ajouter une ligne à une variable tableau d'objets récupérée par la méthode tabCharge de ma classe souhaitée.
    Par exemple, je prends l'exemple de ma classe MProbleme_Contact qui possède une méthode tabCharge pour me renvoyer un tableau de tout les contacts pour un problème donné. Admettons que j'ai créé une variable "TableauProblemeContact" qui est un tableau de MProbleme_Contact, j'utilise donc ma méthode tabCharge de MProbleme_Contact afin de le remplir. Là c'est ok.

    Mais maintenant, si je veux ajouter une ligne (ou supprimer peu importe) à cette variable "TableauProblemeContact", dois-je avoir une méthode dans ma classe MProbleme_Contact "tabAjoute" et passer en paramètre de ma méthode la variable tableau de MProbleme_Contact avec comme code :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    PROCÉDURE tabAjoute(tabContact est un tableau de MProbleme_Contact) <métier>
    TableauAjoute(tabContact ,objet)
    et donc pour ajouter une ligne à cette variable tableau, j'instancie un objet (exemple : UnPbContact) de MProbleme_Contact que je remplie, et j'appelle ensuite la méthode tabAjoute en passant en paramètre le tableau :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    UnPbContact.tabAjoute(TableauProblemeContact)
    Ou alors ça ne se fait pas d'avoir dans la même classe, à la fois une méthode qui va me renvoyer un tableau de cette classe, et des méthodes qui vont me permettre d'ajouter, supprimer des lignes au tableau, sachant que ce tableau n'est pas directement un membre de ma classe (donc obligé de le passer en paramètre comme j'ai fait ci-dessus) ?


    Ou 2ème possibilité toujours dans l'exemple d'ajouter une ligne à cette variable tableau, je dois faire cet ajout directement dans ma classe présentation via la méthode :
    UnPbContact est un MProbleme_Contact, je remplie cet objet et ensuite je fais un tableauajoute(TableauProblemeContact,UnPbContact) (toujours dans la méthode de la classe Présentation)


    Ou 3eme possibilité, je créé une classe indépendante MTableauDeMProbleme_Contact qui possède comme membre un tableau de ma classe avec dedans les méthodes tabAjoute, tabSupprime, tabCharge :
    MTableauDeProbleme_Contact est une classe
    m_tabProblemeContact est un tableau de MProbleme_Contact dynamique

    et dans ce cas coté classe présentation, je déclarerais un objet (exemple MonObjet) de MTableauDeMProbleme_Contact et appellerait ses méthodes pour charger, ajouter ligne etc :
    MonObjet.tabAjoute(UnPbContact) //UnPbContact = Un objet de MProbleme_Contact

    Cette 3ème possibilité est utilisé dans l'exemple MVP de PCSOFT mais oblige pour chaque fichier de l'analyse de créer en plus de la classe mappée une classe Tableau de cette classe mappée. Donc 2 classes par fichier, pas top top...


    Cordialement,
    Esteban

  4. #4
    Membre expérimenté

    Homme Profil pro
    Sans
    Inscrit en
    Mars 2018
    Messages
    153
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Sans

    Informations forums :
    Inscription : Mars 2018
    Messages : 153
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Djsven Voir le message
    Salut Padbrain, merci d'avoir pris le temps de me répondre,



    Je voyais justement la classe "Présentation" comme la couche façade me permettant justement d'y faire mes traitements. Avant de penser à cette classe intermédiaire, je manipulais mes actions avec mes classes modèles dans des procédures locales/globales, c'est pour cela que je me suis dit que ça serait sans doute plus propre d'ajouter cette classe intermédiaire qui, selon les actions utilisateurs cotés UI, me permettrait de manipuler mes classes modèles. C'est pour cela aussi que je m'y perd un peu, à savoir si je dois plutôt écrire ma méthode coté classe modèle, ou plutôt coté classe intermédiaire "présentation". Je reprendrais dans la suite de mon message l'exemple de l'ajout d'une ligne à un tableau que j'ai récupéré à partir d'une méthode d'une classe.
    Lorsque je parle de façade, je pense surtout au patron de conception éponyme : https://fr.wikipedia.org/wiki/Fa%C3%...de_conception).

    Dans ce diagramme, les Packages correspondent à tes classes de mapping et les clients correspondent aux classes de présentation.

    Rien ne t'empêche d'utiliser tes classes de présentation comme une façade (bien que ce ne soit pas leur rôle) mais lorsque tu manipuleras des notions métier plus complexes qui demanderont une utilisation conjointe de tes classes modèles, l'implémentation de façades te facilitera grandement la tâche ET la maintenance.

    C'est ce que je faisais aussi, mais étant donné que justement cette variable tableau de MProbleme_Contact est liée à ma classe MProbleme (Un problème peut avoir un ou plusieurs contacts associés, donc mes contacts sont liés à un problème), n'est-ce pas plus propre de définir directement ma variable Tableau de MProbleme_Contact comme un membre de ma classe MProbleme ?

    Donc dans ma classe présentation, plutôt que déclarer ma variable tableau en plus de ma variable objet MProbleme, je déclarerais simplement la variable qui est un objet de MProbleme qui possèdes les membres mappés sur mon fichier d'analyse et qui possède également le tableau de ma classe MProbleme_Contact (Ce dernier sera databindé sur ma table visuelle coté UI). Et j'accéderais au tableau de contacts associés par MonObjProbleme.MontableauDeMProblemeContact ?
    En ce qui me concerne, je ne mettrai pas de membre Tableau de MProbleme_Contact dans la classe MProbleme. MProbleme est, pour moi, destinée uniquement à faire un CRUD sur le fichier Problème.

    Pour les ajouts et suppressions de ligne, je parlais dans la variable publique de mon tableau d'objet, quand j'ai déjà ouvert la fiche pour ajouter et que je valide. 90% du temps après un ajout en bdd je recharge toute la table visuelle afin d'avoir des données à jour, dans ce cas pas de problème je rappelle simplement ma méthode tabCharge de ma classe correspondante. Mais pour certains cas, je dois simplement ajouter une ligne à ma table visuelle sans tout rafraichir (Équivalent d'un tableAjouteLigne()), donc ici un tableauajoute(Tableau mémoire, Objet mémoire) + un tableAffiche() vu que ma table visuelle est databindée sur ma variable tableau.


    Comme j'ai dit plus haut, je m'y perd pour savoir où je dois déclarer ma méthode pour ajouter une ligne à une variable tableau d'objets récupérée par la méthode tabCharge de ma classe souhaitée.
    Par exemple, je prends l'exemple de ma classe MProbleme_Contact qui possède une méthode tabCharge pour me renvoyer un tableau de tout les contacts pour un problème donné. Admettons que j'ai créé une variable "TableauProblemeContact" qui est un tableau de MProbleme_Contact, j'utilise donc ma méthode tabCharge de MProbleme_Contact afin de le remplir. Là c'est ok.
    Si tu as une classe cProblemeContacts, tu peux déclarer dans celle-ci un tableau de MProbleme_Contact que tu alimenterais via une requête SELECT, comme tu dois déjà le faire.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    cProblemeContacts est une Classe
     
    	PRIVÉ
    		_tabProblemeContacts est un tableau de MProbleme_contact
    FIN
    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
     
    PROCÉDURE chargerProblemeContact(pIdProbleme est entier)
     
    requete est une chaîne = [
    	SELECT
    		patati,
    		patata
    	FROM
    		MProblemeContact
    	WHERE
    		idProbleme = %1 
    ]
     
    requete = ChaîneConstruit(requete, pIdProbleme)
     
    resultat est une Source de Données
    HExécuteRequête(requete, hRequêteDéfaut, resultat)
     
    POUR TOUT resultat 
    	_tabProblemeContacts.Ajoute(resultat)
    FIN
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    PROCÉDURE getProblemeContacts()
    RENVOYER _tabProblemeContacts

    Ta classe de présentation peut ensuite utiliser cette classe pour récupérer tous les contacts liés à un problème. Tu isoles ainsi la couche persistence de la couche IHM. La classe de présentation est, pour moi, liée à l'IHM.


    Mais maintenant, si je veux ajouter une ligne (ou supprimer peu importe) à cette variable "TableauProblemeContact", dois-je avoir une méthode dans ma classe MProbleme_Contact "tabAjoute" et passer en paramètre de ma méthode la variable tableau de MProbleme_Contact avec comme code :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    PROCÉDURE tabAjoute(tabContact est un tableau de MProbleme_Contact) <métier>
    TableauAjoute(tabContact ,objet)
    et donc pour ajouter une ligne à cette variable tableau, j'instancie un objet (exemple : UnPbContact) de MProbleme_Contact que je remplie, et j'appelle ensuite la méthode tabAjoute en passant en paramètre le tableau :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    UnPbContact.tabAjoute(TableauProblemeContact)
    Ou alors ça ne se fait pas d'avoir dans la même classe, à la fois une méthode qui va me renvoyer un tableau de cette classe, et des méthodes qui vont me permettre d'ajouter, supprimer des lignes au tableau, sachant que ce tableau n'est pas directement un membre de ma classe (donc obligé de le passer en paramètre comme j'ai fait ci-dessus) ?


    Ou 2ème possibilité toujours dans l'exemple d'ajouter une ligne à cette variable tableau, je dois faire cet ajout directement dans ma classe présentation via la méthode :
    UnPbContact est un MProbleme_Contact, je remplie cet objet et ensuite je fais un tableauajoute(TableauProblemeContact,UnPbContact) (toujours dans la méthode de la classe Présentation)
    Attention, ajouter ou supprimer une ligne dans ta variable n'influe pas sur le contenu de ton fichier. Tu t'exposes, alors, à ne plus avoir ton tableau de visualisation en phase avec le contenu de ton fichier en base.


    Ou 3eme possibilité, je créé une classe indépendante MTableauDeMProbleme_Contact qui possède comme membre un tableau de ma classe avec dedans les méthodes tabAjoute, tabSupprime, tabCharge :
    MTableauDeProbleme_Contact est une classe
    m_tabProblemeContact est un tableau de MProbleme_Contact dynamique

    et dans ce cas coté classe présentation, je déclarerais un objet (exemple MonObjet) de MTableauDeMProbleme_Contact et appellerait ses méthodes pour charger, ajouter ligne etc :
    MonObjet.tabAjoute(UnPbContact) //UnPbContact = Un objet de MProbleme_Contact

    Cette 3ème possibilité est utilisé dans l'exemple MVP de PCSOFT mais oblige pour chaque fichier de l'analyse de créer en plus de la classe mappée une classe Tableau de cette classe mappée. Donc 2 classes par fichier, pas top top...
    C'est, je crois ce que je te propose. Cependant, tu n'es pas obligé de créer une "classe tableau" associée pour toutes tes classes mappées si tu n'en as pas besoin dans ton application .
    Si tu veux séparer tes couches, il faut faire ce qu'il faut

    A mon sens, il te faut une fenêtre pour ajouter un contact et une pour supprimer un contact. Une fois une de ces actions faite, tu peux recharger ta visu tableau à partir de ta requête et ta visu sera alors en phase avec le contenu de ton fichier.
    Ces vues manipulent des MProbleme_contact en CRUD.

    hth,
    Padbrain

  5. #5
    Membre confirmé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Janvier 2020
    Messages
    66
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France, Aisne (Picardie)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Janvier 2020
    Messages : 66
    Par défaut
    Merci pour ta réponse,

    Par contre, pour ma table visuelle de Probleme_Contact sur ma fenêtre Problème, j'ai besoin d'avoir également les colonnes avec le nom du contact (table contact), le prénom du contact (table contact) et le nom de la société du contact (table societe). Or je n'ai pas ça dans ma table jointure Probleme_Contact. J'ai donc fait une requête avec jointure. Mais vu que dans ma table de jointure Probleme_Contact je n'ai que l'id du contact, l'id du probleme et le commentaire, j'ai ajouté un membre objet de MContact à ma classe MProbleme_Contact (voir ci dessous), et dans ma classe MContact un membre objet de MSociete. Je remplie ainsi mon tableau de MProbleme_Contact via des fichiersversmémoire successif (objet MProbleme_Contact, sous objet MContact et sous sous objet MSociete) (Voir ci-dessous).

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    MProbleme_Contact est une Classe <MAPPING=Probleme_Contact>
    	hérite de MBase
    	<MAPPING>
    	m_nPBcode		est un entier sans signe sur 4 octets	<MAPPING=PBcode>
    	m_sCONTcode		est une chaîne ANSI						<MAPPING=CONTcode>
    	m_sPBCNTcom	est une chaîne ANSI						<MAPPING=PBCNTcom>
    	<FIN>
    	
    	m_pclContact est un MContact dynamique //MContact quant-à lui possède un membre m_pclSociete est un MSociete dynamique
    FIN
    Ma classe MTableauDeProbleme_Contact (équivalent à ton cProblemeContact) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    MTableauDeProbleme_Contact est une Classe
    	m_tabContact		est un tableau de MProbleme_Contact dynamique
    FIN
    qui possède une méthode pour charger le tableau :

    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
    PROCÉDURE chargerProblemeContact(nProblemeCode,clErreur est un CErreur) <métier>
     
    SupprimeTout(m_tabContact)
     
    MaRequete est une Requête SQL = 
    [
    	SELECT 
    	Probleme_Contact.PBcode AS PBcode,
    	Probleme_Contact.CONTcode AS CONTcode,
    	Probleme_Contact.PBCNTcom AS PBCNTcom,
    	Contact.CONTnom AS CONTnom,
    	Contact.CONTprenom AS CONTprenom,
    	Societe.SOCnom AS SOCnom
    	FROM Probleme_Contact
    	INNER JOIN Contact ON Probleme_Contact.CONTcode	= Contact.CONTcode
    	LEFT OUTER JOIN Societe ON Contact.SOCcode = Societe.SOCcode
    	WHERE Probleme_Contact.PBcode = {ParamPBcode}
    	ORDER BY CONTnom ASC, CONTprenom ASC
    ]
     
    MaRequete.ParamPBcode = nProblemeCode
    SI PAS HExécuteRequête(MaRequete,hRequêteDéfaut) ALORS 
    	clErreur.Init(CErreur::ErreurSQL)
    	RENVOYER Faux
    FIN
    POUR TOUT MaRequete 
    	clUnContact est un MProbleme_Contact
    	clUnContact.m_pclContact <- allouer un MContact
    	clUnContact.m_pclContact.m_pclSociete <- allouer un Msociete
    	clUnContact.ChargeElement(MaRequete..Nom) //Equivalent à WL.FichierVersMémoire(clUnContact,MaRequete..Nom)
    	WL.FichierVersMémoire(clUnContact.m_pclContact,MaRequete..Nom)
    	WL.FichierVersMémoire(clUnContact.m_pclContact.m_pclSociete,MaRequete..Nom)
    	TableauAjoute(m_tabContact,clUnContact)
    FIN
    HLibèreRequête(MaRequete)

    Est-ce que cela se fait ? Je rappelle que ma table Probleme_Contact est la table jointure de Probleme et de Contact (avec une rubrique commentaire en plus des deux id qui font la liaison dans la table)


    Car d'un autre côté, quelqu'un m'a dit de créer un tableau de MContact (et non pas MProbleme_Contact car apparemment ça ne se fait pas de travailler sur les tables jointures) dans ma classe MProbleme. De faire une requête pour récupérer les Contact ID de ma table Probleme_Contact pour remplir ce tableau de MContact. Et ensuite de parcourir chaque Contact de mon tableau, d'allouer un objet Societe en passant l'id société du contact et de charger l'objet société (Donc un Hlitrecherchepremier sur la table société), puis ensuite d'allouer un objet MProbleme_Contact en passant l'id probleme et l'id contact et de charger l'objet (autre hlitrecherchepremier sur table Probleme_Contact) pour récupérer le commentaire présent dans Probleme_Contact.
    Le problème de cette solution, qui apparemment se fait de cette façon en JAVA pour la POO, c'est que je dois exécuter une première requête pour récupérer mes contacts lié à un problème, et ensuite parcourir mon tableau de MContact et faire deux HlitRecherchePremier (Donc deux autres actions/requêtes sur le serveur) pour récupérer tout ce dont j'ai besoin. C'est opti de faire ça ? J'avais lu quelque part qu'il fallait justement éviter de faire plusieurs hlitrecherchepremier dans une boucle de parcourt mais je me trompe peut-être.



    Attention, ajouter ou supprimer une ligne dans ta variable n'influe pas sur le contenu de ton fichier. Tu t'exposes, alors, à ne plus avoir ton tableau de visualisation en phase avec le contenu de ton fichier en base.
    Oui je me doute bien, c'était dans le cas où j'ouvre une fiche pour ajouter un élément, que je l'enregistre en BDD et qu'à la sortie, j'ajoute simplement cet élément à mon tableau mémoire pour éviter de tout rafraîchir. C'est surtout utile dans le cas où j'ouvre une fiche pour ajouter un élément qui ne doit pas être directement enregistré en BDD mais une fois que l'utilisateur valide tout (donc je ne peux pas rafraîchir toute ma table, je dois ajouter mes lignes à mon tableau et ensuite parcourir ce tableau pour justement enregistrer en BDD). Exemple : Je crée une commande, j'ai une table produits, donc j'ajoute mes produits en mémoire (Tableau) avant de tout enregistrer à la validation via le parcourt de ce tableau.


    C'est, je crois ce que je te propose. Cependant, tu n'es pas obligé de créer une "classe tableau" associée pour toutes tes classes mappées si tu n'en as pas besoin dans ton application
    Je pense que j'en aurais besoin pour beaucoup de classes, vu que même pour remplir un combo avec des éléments qui proviennent d'une table de mon analyse, je dois créer un tableau et databindé le tableau sur mon combo , y'a peut-être moyen de créer une classe générique de tableau pour éviter de retaper à chaque classe tableau de classes les méthodes "AjoutElementAuTableau" "SupprimeElementDuTableau" "ModifieElementDuTableau" et "ChargeTableau"

    A mon sens, il te faut une fenêtre pour ajouter un contact et une pour supprimer un contact. Une fois une de ces actions faite, tu peux recharger ta visu tableau à partir de ta requête et ta visu sera alors en phase avec le contenu de ton fichier.
    Ces vues manipulent des MProbleme_contact en CRUD.
    Oui c'est ce que je comptais faire pour la plupart des cas, j'ai déjà mes fenêtres pour ajouter/modifier un élément avec ajout/modif en bdd à la validation. Puis je recharge pour avoir les données à jour après validation.


    Merci


    Esteban

  6. #6
    Membre confirmé
    Profil pro
    Inscrit en
    Janvier 2008
    Messages
    140
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2008
    Messages : 140
    Par défaut
    bonjour
    je trouve votre démarche vraiment intéressante. Seriez-vous prêt de mettre à dispo votre projet exemple.
    cela permettrait de mieux comprendre ce genre de concept via windev

Discussions similaires

  1. POO : Création d'un système question/réponses
    Par Kenshin_Himura dans le forum Langage
    Réponses: 0
    Dernier message: 03/05/2010, 23h49
  2. Réponses: 0
    Dernier message: 24/09/2008, 17h03
  3. [Architecture] Question d'architecture
    Par bourbaki2003 dans le forum Général Java
    Réponses: 3
    Dernier message: 11/07/2006, 10h38
  4. [Architecture] Questions DB, Arch, Tech pour un project
    Par Ultiny dans le forum Développement Web en Java
    Réponses: 3
    Dernier message: 02/05/2006, 15h04
  5. [Architecture] Question data layer et présentation
    Par brousaille dans le forum Plateformes (Java EE, Jakarta EE, Spring) et Serveurs
    Réponses: 16
    Dernier message: 14/01/2006, 12h48

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