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

VB.NET Discussion :

Probleme d'Inheritance / Structuration du code


Sujet :

VB.NET

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éclairé
    Inscrit en
    Mars 2006
    Messages
    342
    Détails du profil
    Informations forums :
    Inscription : Mars 2006
    Messages : 342
    Par défaut Probleme d'Inheritance / Structuration du code
    Bonjour,

    Voici mon probleme. Je suppose qu'il est trivial pour quelqu un qui maitrise le jonglage entre classes, mais il ne l est pas pour moi ...

    Dans une base de donnees, j ai des elements qui sont TOUS des noeuds. Or certains de ces noeuds sont des reservoirs et ont donc des attributs que les autres noeuds n'ont pas (par exemple une capacité de stockage d'eau), mais ont tous les attributs des noeuds.

    C'est pourquoi, j ai crée une classe My_node avec tous les attributs des noeuds :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    Public Class My_node
        Public node_id As Integer
        Public type_id As Integer
        Public name As String
        Public X As Single
        Public Y As Single
        Public Water_company As String
        Public WRZ As String
        Public RWSM_type As String
    End Class
    et une classe My_Reservoir qui inherite de ma classe My_node a laquelle j'ajoute les attributs specifiques a un reservoir (Capacity et Initial Storage):

    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
    Public Class My_Reservoir
        Inherits My_node
        Public Capacity As Integer
        Public Initial_Storage As Integer
     
        Sub Fromnode(ByVal anode As My_node)
            Me.name = anode.name
            Me.node_id = anode.node_id
            Me.RWSM_type = anode.RWSM_type
            Me.type_id = anode.type_id
            Me.Water_company = Me.Water_company
            Me.WRZ = anode.WRZ
            Me.X = anode.X
            Me.Y = anode.Y
        End Sub
    End Class
    (Notez la Sub Fromnode car ma question porte sur ca)

    De plus, chaque noeud (et donc aussi reservoir) est attribué à ce que j appelle une "water resource zone" (WRZ). qui est donc un groupe noeuds. D'ou Ma classe My_WRZ :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    Public Class My_WRZ
        Public Water_company As String
        Public WRZ As String
        Public WRZ_Reservoir As New My_Reservoir
        Public WRZ_Junction As New My_node
        Public WRZ_WTW As New My_node
        Public WRZ_Dembis As New My_node
        Public WRZ_Dem As New My_node
    End Class
    COmme vous pouvez le voir ci-dessus, une WRZ contient donc des noeuds classiques (My_node) et un reservoir (My_reservoir).

    Vous suivez jusque la ?

    Dans ma Forme (je connais pas le nom en francais sry), j'utilise 2 dictionnaires. Un pour mes noeuds et un pour Mes WRZ :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
      Dim Dico_nodes As New Dictionary(Of Integer, My_node)
    Dim Dico_WRZ As New Dictionary(Of String, My_WRZ)
    Ce que je souhaite faire est donc de lire les attributs de chaque noeud de ma base de données. Les ajouter a mon dictionnaire de noeuds, puis mettre a jour mon Dictionnaire de WRZ.

    Le code que j utilise (et qui semble fonctionner) est le suivant:


    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
    Dim SQLreader1 As SQLiteDataReader = SQLcommand1.ExecuteReader()
            While SQLreader1.Read()
                Dim Anode As New My_node
                Anode.node_id = SQLreader1(0)
                Anode.type_id = SQLreader1(2)
                Anode.name = SQLreader1(3)
                Anode.X = SQLreader1(5)
                Anode.Y = SQLreader1(6)
                Anode.Water_company = SQLreader1(7)
                Anode.WRZ = SQLreader1(8)
                Anode.RWSM_type = SQLreader1(9)
                Dico_nodes.Add(Anode.node_id, Anode)
     
                If Dico_WRZ.ContainsKey(Anode.WRZ) = False Then
                    Dim AWRZ As New My_WRZ
                    AWRZ.Water_company = Anode.Water_company
                    AWRZ.WRZ = Anode.WRZ
                    Dico_WRZ.Add(AWRZ.WRZ, AWRZ) 
                End If
     
                If Anode.RWSM_type = "WRZ Reservoir" Then
                    Dico_WRZ(Anode.WRZ).WRZ_Reservoir.Fromnode(Dico_nodes(Anode.node_id))
                ElseIf Anode.RWSM_type = "WRZ WTW" Then
                    Dico_WRZ(Anode.WRZ).WRZ_WTW = Dico_nodes(Anode.node_id)
                ElseIf Anode.RWSM_type = "WRZ Junction" Then
                    Dico_WRZ(Anode.WRZ).WRZ_Junction = Dico_nodes(Anode.node_id)
                ElseIf Anode.RWSM_type = "WRZ Dembis" Then
                    Dico_WRZ(Anode.WRZ).WRZ_Dembis = Dico_nodes(Anode.node_id)
                ElseIf Anode.RWSM_type = "WRZ Dem" Then
                    Dico_WRZ(Anode.WRZ).WRZ_Dem = Dico_nodes(Anode.node_id)
                End If
     
            End While
            SQLreader1.Close()
    Mon probleme est que je ne comprends pas pourquoi si mon noeud est un reservoir, je doive utiliser la ligne de code suivante sans pouvoir tout simplement dire que tel noeud est le reservoir de ma WRZ.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Dico_WRZ(Anode.WRZ).WRZ_Reservoir.Fromnode(Dico_nodes(Anode.node_id))
    Je suis quasiment sur que ce que j ai ecris dans mon code est du bidouillage bancal, mais je n'arrive pas a mettre le doigt sur une solution plus "propre" ...

    Merci.

    Slumpy

  2. #2
    Membre Expert Avatar de DonQuiche
    Inscrit en
    Septembre 2010
    Messages
    2 741
    Détails du profil
    Informations forums :
    Inscription : Septembre 2010
    Messages : 2 741
    Par défaut
    Bonjour à toi.

    Ta solution fonctionne et il n'y a pas de façon tellement plus courte ou élégante de faire. En revanche, elle est difficilement lisible, peu résistante aux changements et inhabituelle (donc plus difficilement compréhensible au premier abord).

    Concernant la lecture depuis la DB, j'aurais d'abord testé RWSM_type et choisi en fonction de ça d'instancier soit un noeud, soit un réservoir.

    Qui plus est, j'aurais créé sur Noeud un constructeur acceptant un SQLReader. Réservoir aurait un constructeur équivalent, s'appuyant sur celui de Noeud. A chaque classe la responsabilité de se lire depuis la DB donc.

    J'aurais défini sur WRZ un indexeur dont l'index serait le type RWSM. Et j'aurais créé une énumération pour ce type plutôt de manipuler directement des chaînes (la conversion se faisant une fois pour toutes au niveau de la lecture depuis la DB). L'énumération est beaucoup plus propre et évite de bêtes erreurs tout en permettant un refactoring aisé. Et l'indexeur permet de confier à WRZ la reponsabilité de retourner/assigner le noeud correspondant au type spécifié.

    Enfin, j'aurais passé mes champs en privé et je n'aurais laissé que des propriétés, au cas où je veuille changer plus tard les détails de l'implémentation de mes classes.

    Dernière remarque : le nommage. Pourquoi ajouter ce préfixe WRZ à tous les membres de WRZ ? Et toutes ces abréviations seront-elles toujours évidentes quand tu reliras ce code dans un an ? Enfin, dans la mesure où MS a utilisé CamelCase pour le framework, on préfère généralement cette convention pour les projets dotnet, par souci d'homogénéité.

  3. #3
    Membre extrêmement actif
    Inscrit en
    Avril 2008
    Messages
    2 573
    Détails du profil
    Informations personnelles :
    Âge : 65

    Informations forums :
    Inscription : Avril 2008
    Messages : 2 573
    Par défaut reseau hydraulique,et dicos nodes.
    bonjour Slumpy
    Il me semble que ton souci de gestion de reseau hydraulique aurait gagne à etre analyse un peu plus.
    Pourquoi heriter d'un noeud My_Node en creant un noeud specifique Reservoir (reservoir est un attribut de noeud d'ailleur comme junction,vanne dans ta bd etc....) et stocker tous les champs dans celui-ci.

    Il suffit d'une association avec une prop referencant le noeud qui le contient (une petite adresse en memoire) car un reservoir est ......un noeud.
    Par ailleurs la creation ou instanciation d'un My_Reservoir necessite au prealable celle d'un My_Node (pas de reservoir ....flottant dans le reseau).

    Relativement au dico des zones il est bon mais peche par un petit defaut .
    J'aurais prefere que chaque zone contiennent un Dico par type ou attribut de noeud(reservoir ,junction,vanne etc....) au lieu d'un class My_Node.
    Dicos dont on a besoin pour classer et lister les differents types de noeuds du reseau existant.
    Modification du code:
    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
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
     
    'sans changement
    Public Class My_nodeBis
        Public node_id As Integer
        Public type_id As Integer
        Public name As String
        Public X As Single
        Public Y As Single
        Public Water_company As String
        Public WRZ As String
        Public RWSM_type As String
    End Class
     
    'Association au lieu d'heritage
    Public Class My_ReservoirBis
        Public Capacity As Integer
        Public Initial_Storage As Integer
     
        'prop avec reference sur noeud support
        Private m_refnode As My_nodeBis
     
        Public Sub New(ByVal objNode As My_nodeBis)
            Me.m_refnode = objNode
        End Sub
        'a supprimer
        'Sub Fromnode(ByVal objNode As My_nodeBis)
        '    Me.m_refnode = objNode
        'End Sub
     
        Public Property RefNode() As My_nodeBis
            Get
                Return m_refnode
            End Get
            Set(ByVal value As My_nodeBis)
                m_refnode = value
            End Set
        End Property
     
    End Class
     
    'Dicos par attribut noeud
    Public Class My_WRZBis
        Public Water_company As String
        Public WRZ As String
        'Dico par type de noeud
        Public WRZ_Reservoir As New Dictionary(Of String, My_ReservoirBis)
        Public WRZ_WTW As New Dictionary(Of String, My_nodeBis)
        Public WRZ_JunctionBis As New Dictionary(Of String, My_nodeBis)
        Public WRZ_Dembis As New Dictionary(Of String, My_nodeBis)
        Public WRZ_Dem As New Dictionary(Of String, My_nodeBis)
     
        Public Sub New()
        End Sub
    End Class
     
     
    Public Class Form2
        Dim Dico_NodesBis As New Dictionary(Of Integer, My_nodeBis)
        Dim Dico_WRZBis As New Dictionary(Of String, My_WRZBis)
     
        Private Sub Form2_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
            Dim SQLreader1 As SqlClient.SqlDataReader = SQLcommand1.ExecuteReader()
            While SQLreader1.Read()
                Dim Anode As New My_nodeBis
                Anode.node_id = SQLreader1(0)
                Anode.type_id = SQLreader1(2)
                Anode.name = SQLreader1(3)
                Anode.X = SQLreader1(5)
                Anode.Y = SQLreader1(6)
                Anode.Water_company = SQLreader1(7)
                Anode.WRZ = SQLreader1(8)
                Anode.RWSM_type = SQLreader1(9)
                Dico_NodesBis.Add(Anode.node_id, Anode)
     
                Dim AWRZ As My_WRZBis
                If Dico_WRZBis.ContainsKey(Anode.WRZ) = False Then
                    'nouvelle zone
                    AWRZ = New My_WRZBis
                    AWRZ.Water_company = Anode.Water_company
                    AWRZ.WRZ = Anode.WRZ
                    Dico_WRZBis.Add(AWRZ.WRZ, AWRZ)
                End If
                AWRZ = Dico_WRZBis(Anode.WRZ)
                Select Case Anode.RWSM_type
                    Case "WRZ Reservoir"
                        Dim objReservoir As New My_ReservoirBis(Anode)
                        AWRZ.WRZ_Reservoir.Add(Anode.name, objReservoir)
                    Case "WRZ WTW"
                        AWRZ.WRZ_WTW.Add(Anode.name, Anode)
                    Case "WRZ Junction"
                        AWRZ.WRZ_JunctionBis.Add(Anode.name, Anode)
                    Case "WRZ Dembis"
                        AWRZ.WRZ_Dembis.Add(Anode.name, Anode)
                    Case "WRZ Dem"
                        AWRZ.WRZ_Dem.Add(Anode.name, Anode)
                End Select
     
                'If Anode.RWSM_type = "WRZ Reservoir" Then
                '    Dico_WRZ(Anode.WRZ).WRZ_Reservoir.Fromnode(Dico_nodes(Anode.node_id))
                'ElseIf Anode.RWSM_type = "WRZ WTW" Then
                '    Dico_WRZ(Anode.WRZ).WRZ_WTW = Dico_nodes(Anode.node_id)
                'ElseIf Anode.RWSM_type = "WRZ Junction" Then
                '    Dico_WRZ(Anode.WRZ).WRZ_Junction = Dico_nodes(Anode.node_id)
                'ElseIf Anode.RWSM_type = "WRZ Dembis" Then
                '    Dico_WRZ(Anode.WRZ).WRZ_Dembis = Dico_nodes(Anode.node_id)
                'ElseIf Anode.RWSM_type = "WRZ Dem" Then
                '    Dico_WRZ(Anode.WRZ).WRZ_Dem = Dico_nodes(Anode.node_id)
                'End If
     
            End While
            SQLreader1.Close()
        End Sub
        'Iteration dans les differents Dicos
        Private Sub btnIteration_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnIteration.Click
            'Find zone
            Dim nameZone As String
            Dim currentZone As My_WRZBis
            For Each kv As KeyValuePair(Of String, My_WRZBis) In Dico_WRZBis
                nameZone = kv.Key
                currentZone = kv.Value
                'Display namezone,type zone
                MessageBox.Show(nameZone & currentZone.Water_company & currentZone.WRZ)
            Next
            'Find node
            For Each currentNode As My_nodeBis In Dico_NodesBis.Values
                nameZone = currentNode.WRZ
                If Dico_WRZBis.ContainsKey(nameZone) Then
                    'Display reservoir
                    For Each xReservoir As My_ReservoirBis In Dico_WRZBis(nameZone).WRZ_Reservoir.Values
                        MessageBox.Show(xReservoir.RefNode.name & xReservoir.RefNode.WRZ & xReservoir.Capacity)
                    Next
     
                    'Display WRZ Junction
                    For Each xNodeJunction As My_nodeBis In Dico_WRZBis(nameZone).WRZ_JunctionBis.Values
                        MessageBox.Show(xNodeJunction.name & xNodeJunction.WRZ)
                    Next
     
                End If
     
            Next
        End Sub
     
       'Recherche d'un element dans les differents Dicos
        Private Sub btnRecherche_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnRecherche.Click
            'Retrouve une zone dans Values avec la cle
            Dim nameZone As String = "Zone1"
            Dim currentZone As My_WRZBis = Dico_WRZBis(nameZone)
     
            'Retrouve un noeud type "WRZ Reservoir" avec la cle "nom du noeud support"
            Dim xnode1 As My_nodeBis
            'Test d'existance  de cle est -toujour indispensable- dans un dico. 
            If Dico_WRZBis(nameZone).WRZ_Reservoir.ContainsKey(xnode1.name) Then
                Dim currentReservoir As My_ReservoirBis = Dico_WRZBis(nameZone).WRZ_Reservoir(xnode1.name)
     
            End If
     
     
            'Retrouve un noeud type "WRZ Junction" avec la cle "nom du noeud support"
            Dim xnode2 As My_nodeBis
            'Test d'existance  de cle est -toujour indispensable- dans un dico. 
            If Dico_WRZBis(nameZone).WRZ_JunctionBis.ContainsKey(xnode2.name) Then
                Dim currentNodeJunction As My_nodeBis = Dico_WRZBis(nameZone).WRZ_JunctionBis(xnode2.name)
            End If
     
     
        End Sub
    End Class
    Quant au fromnode qui t'embete c'est en fait un simple sub New dans la classe My_Reservoir avec argument de type My_Node et un Property RefNode qui garde une reference dessus.

  4. #4
    Membre éclairé
    Inscrit en
    Mars 2006
    Messages
    342
    Détails du profil
    Informations forums :
    Inscription : Mars 2006
    Messages : 342
    Par défaut
    Woaw Mabrouki et DonQuiche ... ca c'est de la reponse ! Merci d avoir pris de votre temps les gars.

    Je vais essayer de repondre de mon mieux, mais je dois tout d abord preciser (meme si vous avez du vous en rendre compte ...) que je ne suis pas dutout informaticien ... Donc je dois me gratter la tete pour comprendre ...

    @ DonQUiche

    elle est difficilement lisible, peu résistante aux changements et inhabituelle (donc plus difficilement compréhensible au premier abord).
    Effectivement, j en ai tout a fait conscience. Comme je disais je ne suis pas informaticien et ma programmation est plutot "quick and durty style". En gros, des que cela fait ce que je desire je suis content ... Si t'as une idee de comment je pourrais ameliorer cela (sans que cela prenne 10 ans) je suis prenneur !



    Concernant la lecture depuis la DB, j'aurais d'abord testé RWSM_type et choisi en fonction de ça d'instancier soit un noeud, soit un réservoir.
    Ok, je comprends, et effectivement ca semble etre une bonne idee, merci !



    Qui plus est, j'aurais créé sur Noeud un constructeur acceptant un SQLReader. Réservoir aurait un constructeur équivalent, s'appuyant sur celui de Noeud. A chaque classe la responsabilité de se lire depuis la DB donc.
    Je pense avoir compris mais ne suis pas sur a 100%. Ce que tu dis c'est qu'au lieu de creer Dim Anode As New My_node, puis de "remplir" chaque attribut, tu les aurais passé des la creation du noeud : Dim Anode As New My_node(SQLreader1(0),SQLreader1(1)...) , c'est ca ?
    Effectivement ca reduira la longueur de mon code dans ma Forme. Merci !



    J'aurais défini sur WRZ un indexeur dont l'index serait le type RWSM. Et j'aurais créé une énumération pour ce type plutôt de manipuler directement des chaînes (la conversion se faisant une fois pour toutes au niveau de la lecture depuis la DB). L'énumération est beaucoup plus propre et évite de bêtes erreurs tout en permettant un refactoring aisé. Et l'indexeur permet de confier à WRZ la reponsabilité de retourner/assigner le noeud correspondant au type spécifié.
    Arf, par contre ici, j ai eu beau lire ton paragraphe plusieurs fois, je n ai pas compris ce que tu voulais dire. Tu pourrais expliquer stp ?



    Enfin, j'aurais passé mes champs en privé et je n'aurais laissé que des propriétés
    Je me rappele avoir lu quelque part, que lorsque le code etait relativement court, il n etait pas utile d utiliser des champs privés et y acceder grace a des propriétés d'instance. Si je comprends bien tu recommandes de tjs faire cela, c'est ca ?



    au cas où je veuille changer plus tard les détails de l'implémentation de mes classes.
    Je ne comprends pas ce que cela change de ce point de vue ?



    Dernière remarque : le nommage. Pourquoi ajouter ce préfixe WRZ à tous les membres de WRZ ? Et toutes ces abréviations seront-elles toujours évidentes quand tu reliras ce code dans un an ?
    J'utilise le Prefixe WRZ car en fait, par la suite je vais avoir un autre jeux de noeuds (reservoir, Junction, WTW) qui eux ne font pas parti d'une water resource zone. Donc en fait, c'est juste pour me rappeler que pour l instant je travaille sur les wrz uniquement.
    En ce qui concerne les abreviations (que ce soit le nom des attributs), nodes, wrz, oui je ne pense pas qu il y aura un probleme. (Il faut savoir que je travaille en Angleterre, d'ou des mots anglais plutot que francais).



    Enfin, dans la mesure où MS a utilisé CamelCase pour le framework, on préfère généralement cette convention pour les projets dotnet, par souci d'homogénéité.
    Arf, encore un passage que je ne comprends pas, desolé ... Tu pourrais expliquer stp ?

    Merci encore pour ton temps, c'est instructif et m'aide a reflechir sur mon probleme et ma maniere de coder !



    @ MABROUKI

    Woaw impressionnant ! Effectivement ce que tu proposes est nettement plus clair / propre et tu sembles avoir bien compris mon probleme.

    Pourquoi heriter d'un noeud My_Node en creant un noeud specifique Reservoir (reservoir est un attribut de noeud d'ailleur comme junction,vanne dans ta bd etc....) et stocker tous les champs dans celui-ci.

    Il suffit d'une association avec une prop referencant le noeud qui le contient (une petite adresse en memoire) car un reservoir est ......un noeud.
    Par ailleurs la creation ou instanciation d'un My_Reservoir necessite au prealable celle d'un My_Node (pas de reservoir ....flottant dans le reseau).
    Ma reponse est tres simple ... parce que je n ai pas ton niveau
    Je pense que ce que tu dis est exactement ce que que je me demandais, sans arriver a le formuler correctement ... Bravo !
    (C'est un peu rageant de voir la clarté de ton code, et de voir comment je galere pour pondre quelque chose de brouillon ...)



    Relativement au dico des zones il est bon mais peche par un petit defaut .
    J'aurais prefere que chaque zone contiennent un Dico par type ou attribut de noeud(reservoir ,junction,vanne etc....) au lieu d'un class My_Node.
    Alors en fait, c'est tout simplement car pour une water resource zone, je n ai qu'un reservoir, une jonction, un Water Treatement Work, un noeud Dem et un noeud Dembis. L interet d'un dico pour chaque attributs est pour le cas ou j'en aurais plusieurs non ? Bien qu au moins en utilisant des dico, je pourrais par la suite en avoir plusieurs si je le souhaite.



    Merci bcp d'avoir pris le temps de lire mon post et modifier mon code. Ca a du te prendre un certain temps Je vais m'y appuyer dessus non seulement dans ce projet, mais sans nul doutes dans mes projets a venir.
    J'etais jusque la bien ennuyé des qu il y avait ce que j appele des sous-classes ...

    Petit detail aussi, je ne pense jamais a utiliser "Case". Je vais essayer de m'en servir.



    Pour aller plus loin
    Comme je le disais a DonQuiche, pour corser la chose, j'ai en plus de mes water resources zones, un certain nombre de jeux de (reservoir, Junction, WTW ....) qui ne sont pas associés a une zone a proprement parlé. (Je les appele des elements "specifiques". Spec Reservoirs, Spec Junctions, Spec WTW ...) Ce sont en fait des parties de mon reseau qui envoient l'eau de leur reservoir dans le reservoirs de plusieurs WRZ et donc les attributs WRZ et Water_company n'ont pas de sens pour ces elements.

    Notez que RWSM_type de ces elements sont legerement differents. (Par example, pour les reservoirs associés a une water resource zone, RWSM_type="WRZ Reservoir", et pour les reservoirs specifiques RWSM_type="Spec Reservoir")

    Je m interroge donc sur la maniere de les implementer ... Devrais je d'apres vous tout simplement considerer ces jeux specifiques comme des wrz bien que certains attributs n'existent pas pour eux ? Ou devrais plutot creer une autre classe (un peu equivalente a My_WRZ)

    Merci encore a vous deux pour votre precieuse aide !

    Slumpy

  5. #5
    Membre Expert Avatar de DonQuiche
    Inscrit en
    Septembre 2010
    Messages
    2 741
    Détails du profil
    Informations forums :
    Inscription : Septembre 2010
    Messages : 2 741
    Par défaut
    De rien.
    Je vais tenter de répondre à tes autres questions.

    1. Nous avons tous commencé par le quick'n dirty je pense. Pour éviter d'attendre dix ans, ma foi, il y a quelques bons bouquins à lire, voire à relire régulièrement. Je vais en citer deux mais une recherche internet avec leurs titres accolés permettrait sans doute de trouver davantage de titres. Le premier est "coder proprement", considéré par beaucoup comme une bible : il enseigne principalement à écrire un code facile à comprendre, maintenir et relire via des questions comme le nommage des variables, la longueur des fonctions, la gestion des erreurs, les tests unitaires, etc. Le second est "Conception et programmation orientées objet" de Bertand Meyer, qui n'enseigne pas la POO mais plutôt son bon usage : quelles classes choisir pour modéliser le problème, etc. Ce dernier date un peu (Eiffel) et contient aujourd'hui quelques lacunes (mentionne t-il SOLID par exemple ? Je ne suis pas sûr) mais ça reste un très bon ouvrage, très formateur et facile à lire.


    2. Pour le constructeur de MyNode, je songeais plutôt à un constructeur qui accepterait directement "SQLreader" comme seul argument : ce serait alors la responsabilité du constructeur de cette classe de savoir que "name" est dans la 3ème colonne par exemple. L'approche est donc différente de ton code actuel (l'original ou ta dernière proposition) où toute la responsabilité de la lecture depuis la DB est concentrée dans une fonction. Il n'y a pas une solution absolument supérieure à l'autre cela dit, elles doivent être envisagées dans le contexte de ton programme dans son entier (Que se passe t-il pour ton code si tu ajoutes un champ à une des tables ? Plus généralement, qu'est-ce qui pourrait être amené à changer et quelles classes seraient alors impactées ? Et quelles responsabilités veux-tu confier à chaque objet ?).


    3. Concernant le type RWSL... Aujourd'hui, tu fais des choses telles que If Anode.RWSM_type = "WRZ Reservoir" Then. Ce que je te propose c'est d'abord de créer une énumération : à la lecture et à l'enregistrement tu fais une conversion entre tes chaînes de caractères et cette énumération afin que, dans tout le reste du programme, tu n'utilises plus que l'énumération : If Anode.RWSM_type = RWSM_Type.Reservoir. Ça évitera des bugs dûs à des fautes de frappe, ça permettra un refactoring aisé, les comparaisons seront plus rapides et c'est plus "propre".

    Ensuite, je te propose de créer un indexeur de ce genre ci sur My_WRZ. On peut ensuite masquer les champs et ne laisser que cet indexeur : WRZ apparaît alors comme un pseudo-dictionnaire de couples (type, noeud). Là encore, ce n'est qu'une proposition, tu peux préfèrer conserver une propriété/champ public par type de noeud dans WRZ. Ou mélanger les deux genres. Quoi qu'il en soit cet indexeur est utile si, à plusieurs reprises, tu vas devoir tester le type pour savoir quelle propriété/champ interroger, comme tu l'as fait dans ton code de déserialisation. Enfin, ça dépend de l'impression que tu veux donner de WRZ : la façon dont tu designes la surface publique d'une classe influe sur la perception qu'en a le programmeur et l'usage qu'il en fera.
    Code vb : 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
    Default Public Property Item(ByVal type As RWSM_type) As My_Node
            Get
                 If type = RWSM_Type.Reservoir Then
                      Return WRZ_Reservoir
                 Else If....
                      ....
            End Get
     
            Set(ByVal node As My_Node)
                 If type = RWSM_Type.Reservoir Then
                      WRZ_Reservoir = node
                 Else If....
            End Set
    End Property
     
    'On peut ensuite utiliser cet indexeur ainsi pour assigner "Anode" au champ WRZ.WRZ_Reservoir :
    Dico_WRZ(Anode.WRZ)(Anode.RWSM_type) = Anode



    4. Sur la question des champs et des propriétés c'est un vaste débat mais le consensus est plutôt de n'utiliser que des propriétés, ne serait-ce que parce que dans la convention de nommage habituelle les champs commencent en minuscule alors que les propriétés commencent en majuscule. Et les propriétés anonymes permettent de faire cela sans rendre le code inutilement verbeux.

    Outre l'esthétique, il y a aussi le fait que, parfois, avoir une propriété permet davantage de services : WPF n'autorise pas le binding vers des champs, XMLSerializer ne sérialise que les propriétés.

    Enfin, on a une dernière raison, qui est tout simplement la maintenabilité dans le cas où une autre assembly est lié à la tienne : tu pourras toujours modifier le code derrière une propriété si tu souhaites par exemple supprimer le champ sous-jacent, et ce sans affecter le lien entre ton assembly et celle qui en dépend. En revanche, tu ne peux rien changer à un champ. Ce genre de considérations est évidemment importante quand on crée une bibliothèque.


    5. Le CamelCase, c'est la notation type "MyNode" par opposition à la tienne. Elle est ainsi appelée à cause de l'effet "bosses de chameau" produit par les majuscules.

    Or, MS a utilisé CamelCase partout a travers dotnet et recommande, par souci d'homogénéité de l'écosystème dotnet, d'utiliser CamelCase pour les classes, méthodes et propriétés et lowerCamelCase ("myIntegerSum") pour les variables locales, les arguments et les champs. Enfin, les champs privés se voient en plus marqués d'un underscore au début, afin d'être aisément différenciés des variables locales dans une fonctions (ex : "_type = type" dans un constructeur, est une assignation du champ "_type" avec la valeur de l'argument "type").

    Dans la mesure où tu as choisi une convention de nommage différente, tu te retrouves à manipuler deux conventions, celles de MS quand tu utilises les classes du framework, et la tienne le reste du temps. On recommande souvent, dans tous les langages, d'utiliser la convention du langage lui-même. Mais encore une fois, c'est aussi une affaire de choix.


    6. Beaucoup de devs, moi y compris, préfèrent de toute façon l'anglais pour les noms : les mots y sont plus courts et plus faciles à composer. Mais il y a une différence entre Node, qui est un nom, ou WRZ, qui est une abbréviation. Mais à toi de voir.


    7. Concernant le champ My_WRZ.WRZ_Reservoir, je pense qu'il serait mieux de le laisser défini comme étant du type "My_Reservoir" : d'abord parce que c'est explicite, ensuite parce que cela empêche des bugs (pas de risque d'assigner un simple "MyNode" à ce champ), enfin parce que tu n'auras pas besoin de cast si tu as besoin d'accéder aux informations "capacity" et "inital_storage".


    8. Sur ta dernière question:
    * Tu dis avoir besoin de types (RWSM) différents. Mais le champ de ANode suffit très bien à les stocker. Donc ta nouvelle zone utilisera des objets de type ANode et peut potentiellement partager plusieurs champs avec tes WRZ actuelles.
    * Tant que faire se peut, on essaie de réutiliser du code. Si tes nouveaux jeux de noeuds ont exactement la même typologie (un noeud DEM + un noeud Junction + ...), alors déjà on sait qu'on devrait utiliser soit la même classe, soit des classes apparentées.
    * Tu dis ne pas avoir besoin de WRZ... Cela veut-il dire que tu n'as qu'une seule zone neutre ? Ou bien te faut-il là aussi un identifiant ? Car un même champ couvrirait alors les zones neutres et les autres et il suffit de lui donner un nom plus approprié comme... ID.
    * Si au final il ne reste que WaterCompany comme seule différence tangible, tu peux aussi bien ne garder qu'une unique classe. Tu peux aussi choisir d'utiliser un mécanisme d'héritage mais ça me paraît inutilement lourdingue : tu vas au final devoir stocker tout le monde en tant que classe de base et, chaque fois que tu auras besoin de connaître la compagnie associée à une zone tu devras caster celle-ci pour lire le champ correspondant.

    En règle générale, mieux vaut pouvoir manipuler tout le monde comme une simple instance de la classe mère, ce qui implique qu'elle offre toutes les infos dont on a besoin à l'extérieur. Dans ce scénario idéal les classes filles se contentent de surcharger certains comportements, sans violer le principe de Liskov pour autant, et elles sont seules à faire usage de leurs infos additionnelles (voir le [url=http://en.wikipedia.org/wiki/Dependency_inversion_principle]Dependency inversion principle). Evidemment, ça n'est pas toujours le bon système et ça viole parfois d'autres principes architecturaux.

  6. #6
    Membre éclairé
    Inscrit en
    Mars 2006
    Messages
    342
    Détails du profil
    Informations forums :
    Inscription : Mars 2006
    Messages : 342
    Par défaut
    Salut DonQuiche,

    1- Merci pour les bouquins. Je vais en commander un de ce pas. Par contre, est ce que tu connais "Code Complete" de Steve McConnell ? En cherchant "coder proprement", je suis tombé sur plusieurs personnes qui conseillaient plutot celui la (notemment car coder proprement semble trop orienté Java d apres eux).


    2- Ok, j ai compris maintenant, merci. Ce que tu proposais est donc d'utiliser dans mon programme principal
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Dim Anode As New My_node(SQLreader1)
    et dans ma classe My_node :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    Public Sub New(ByVal SQLreader As SQLiteDataReader)
            Me.node_id = SQLreader(0)
            Me.type_id = SQLreader(2)
            Me.name = SQLreader(3)
            Me.X = SQLreader(5)
            Me.Y = SQLreader(6)
            Me.Water_company = SQLreader(7)
            Me.WRZ = SQLreader(8)
            Me.RWSM_type = SQLreader(9)
        End Sub

    3- Malheureusement je ne comprends tjs pas ce point ... Desolé. Je pense comprendre l'idee, mais pas la pratique.
    EN fait, il me faudrait changer le data type de RWSM_type de String en autre chose c ca ?

    (Pour Info: RWSM signifie Regional Water System Model)


    4-5-6 Ok merci pour cet eclaircissement


    7- Ouaip tu as tout a fait raison, je vais enlever cela.


    8- Pour essayer d'etre plus clair voici un echantillon de mes donnees :

    Comme tu peux le voir j ai ici 2 WRZ (Southern et RZ7) de deux entreprises differentes (Veolia Water Central et SEW). Pour chacune d'elles j ai donc mes 5 elements (Junction, Dem, WTW, Reservoir, Dembis).

    En plus de cela j'ai aussi des lignes (ici 6) qui n'ont pas de Water_company ni WRZ. Ces lignes correspondent en fait à des parties de mon reseau qui distribuent l'eau sur plusieurs WRZ ou plusieurs entreprises (ici j ai deux jeux).

    Ces jeux speciaux, ce caracterisent dans ma Base de données par le fait:
    - qu'ils n'ont pas d'information dans WRZ ni Water_company
    - le nom de l'attribut RWSM_type est legerement different puisqu il est "Spec ..." au lieu de "WRZ ..."
    - il n'y a pas de Dem ni Dembis pour les jeux speciaux

    Mon probleme est que je ne sais pas trop quelle est la meilleure maniere de capturer ces elements specifiques. Me vaut il mieux creer un nouveau Dico pour les jeux specifiques ou pas ? Utiliser ma classe My_WRZ (meme si Water_company et WRZ n'auront pas de sens, et qu il n y a pas de noeuds Dem ni Dembis) ou creer une nouvelle classe ?

    Bien evidemment il va me falloir modifier ma Base de données, pour pouvoir identifier quels sont les 3 elements appartenant à un meme jeux specifique. Style mettre dans Water_company et WRZ le nom du reservoir specifique (ici Darwell et Powdermill)

    J espere etre plus clair ?

    Merci pour toutes ces info, j'apprends bcp

    Slumpy

Discussions similaires

  1. Réponses: 3
    Dernier message: 01/03/2010, 15h47
  2. [PHP-JS] Probleme de javascript dans un code php
    Par stomerfull dans le forum Langage
    Réponses: 3
    Dernier message: 23/01/2006, 09h33
  3. [PHP-JS] Probleme de javascript dans un code php
    Par stomerfull dans le forum Langage
    Réponses: 20
    Dernier message: 12/01/2006, 13h41
  4. Probleme avec des structures
    Par lenectar dans le forum C
    Réponses: 17
    Dernier message: 30/12/2005, 09h53
  5. [langage] Probleme avec commande system et code
    Par Ludo167 dans le forum Langage
    Réponses: 3
    Dernier message: 14/07/2004, 12h01

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