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

  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

  7. #7
    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
    Bonsoir.

    1. Code complete est effectivement une autre référence. Cela dit je ne l'ai pas lu mais il est tout à fait vraisemblable qu'il soit une bonne alternative à "coder proprement". Par contre il me semble qu'il couvre un champ un peu plus large, comparer les tables des matières pourrait être une bonne idée. Concernant Java, je ne pense pas que ce soit rédhibitoire, surtout si tu travailles en C# qui en est assez proche et alors qu'à ton niveau tu as besoin de concret. Enfin, commencer par le bouquin sur la POO est sans doute une meilleure idée cela dit.

    3. Effectivement, je te propose de remplacer le type de RWSM_type par une énumération. Appelons-la "NodeType" :
    Code vb : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    Enum NodeType
       Reservoir=1
       Wtw=2
       Junction=3
       Dembis=4
       Dem=5
    End Enum
     
    'RWSM_type est alors déclaré ainsi :
    Public RWSM_type As NodeType
     
    'Et on l'utilise ainsi :
    If Anode.RWSM_type = NodeType.Reservoir Then

    Cela dit, ça n'a d'intérêt que si tu comptes utiliser le champ RWSM_type ailleurs que pour la sérialisation/désérialisation (vas-tu avoir besoin de faire des tests pour certains calculs et algorithmes ?). Sinon, autant laisser ce champ sous forme de chaîne de caractères.

    Enfin, il faudra, par commodité, définir une fonction chargée de traduire les chaînes de caractères en la valeur correspondante de l'énumération, et vice-versa. A priori je dirais que des méthodes statiques sur ANode seraint parfaites pour ça (NodeTypeToSQL, NodeTypeFromSQL).



    8. Par souci de clarté, je vais parler de zones publiques (zones anonymes) et privées (tes WRZ actuelles). Corrige-moi si ces termes ne correspondent pas réellement à la situation.

    Puisque les zones publiques n'ont pas besoin des champs Dem, Dembis et Water_Company (laissons WRZ : tu l'utiliseras sans doute comme identifiant, comme tu le disais), ça nous fait trois champs inutiles pour les zones publiques, donc autant avoir deux classes a priori, ça semble plus naturel et élégant.(*) Et puisque le plus petit dénominateur commun est la zone publique, faisons ainsi : une classe mère pour les zones publiques, et une classe fille pour les zones privées. Ou, si tu n'arrives pas à trouver de nom adéquat pour la classe de base ou que cela te semble inélégant ou non-naturel, tu peux opter pour un modèle à trois classe (une base commune, une fille pour les zones publiques, une autre pour les zones privées).

    Cela dit, ces considérations sur les champs ne sont pas suffisantes, d'où mon "a priori". D'habitude on cherche à savoir quelle surface publique (champs, proriétés et méthodes) chaque objet doit offrir. Et c'est plutôt à partir de là qu'on détermine l'héritage. Vérifie donc que les méthodes et propriétés que tu comptes avoir sur tes zones publiques et privées concordent avec le modèle à deux classes que je t'ai proposé. Depuis le début je trouve un peu curieux de voir ces classes n'ayant pas de méthodes : considérer uniquement les champs, ça aurait un sens si on devait être conservateur vis-à-vis de la mémoire mais là ce n'est sans doute pas le problème. Ici, on va surtout vouloir des objets propres, faciles à manipuler.

    J'en arrive à ma dernière remarque, qui aborde la dernière de tes questions, concernant l'usage d'un seul ou de deux dictionnaires. Tu te rappelles quand je t'avais dit qu'utiliser des propriétés avait bien des avantages ? Et bien en voici un exemple : tu peux tout à fait, sur ta classe mère (correspondant aux zones publiques), définir une propriété virtuelle "Dem" qui renverra toujours null, ou qui lèvera une exception si on tente d'y assigner quelque chose. Puis surcharger cette propriété dans ta classe fille (correspondant aux zones privées) pour qu'elle devienne un wrapper autour du champ correspondant. Si tu utilises ce genre de mécanismes, alors le seul moment où tu auras à te préoccuper du type réel des classes, ce sera lors de l'instanciation. Le reste du temps tu manipuleras toutes tes zones à travers le seul type de la classe de base (de même qu'on peut manipuler un FileStream, un MemoryStream ou un GzipStream de la même façon, simplement en tant que Stream puisque cette classe de base fournit toutes les méthodes et propriétés - la surface publique - dont a besoin).

    Ce dernier conseil, c'est l'application de mon dernier paragraphe d'hier. Et si tu fais cela, tu n'as besoin que d'un seul dictionnaire puisque, encore une fois, hormis lors de l'instanciation, tu manipuleras tout à travers la seule classe de base, quels que soient les types réels de tes zones. De ce que je sais de ton application, c'est probablement le bon choix, bien meilleur que de parsemer ton code de tests sur le types et de casts ad hoc. Maintenant, il se peut que ce ne soit pas le cas, à cause de la façon dont tu prévois, au travers de tes algorithmes, de manipuler tes zones publiques et privées. Ou parce que tu aboutis à un résultat peu élégant. Ou...

    Souvent, on fait des compromis : par exemple, si tu regardes WinForms, tout le monde hérite de la classe Control. Et Control fournit des propriétés qui sont utiles pour presque tous les contrôles : background, foreground, etc. C'est une bonne chose parce que ça permet par exemple de passer en revue tous les contrôles pour changer les couleurs sans se soucier de leur type réel, ce qui n'aurait pas été possible si chaque contrôle avait eu sa propre propriété "background". Et cela a évité à Microsoft de réécrire du code pour ces propriétés dans chaque contrôle. Mais est-ce qu'il aurait été bon d'aller plus loin et d'ajouter, par exemple, à Control, une propriété Image qui n'aurait servi qu'au contrôle PictureBox ? Non, on ne comprendrait pas vraiment ce qu'elle vient faire là, elle pourrait entraîner de la confusion chez l'utilisateur qui verrait cela, ce serait un gaspillage mémoire, etc.

    PS : Si tu as perdu le fil, pars sur un modèle à deux ou trois classes.

  8. #8
    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 autres zones que des water resources
    bonjour Slumpy
    En complement à ce qu'as dit Don Quiche,on peut donner des orientations generales mais tout depend de l'objectif vise par ton application car toutes ces donnees, plus que probablement, vont servir à ma connaissance :
    1/Soit une application de calcul technique de flots hydrauliques:
    -proprietes fonctionnelles d'un node :debit injecte ou recu dans un node,debit sortant ,depassement de capacite d'un noeud pour un type reservoir ....etat manoeuvrable d'une node(closed ou opened),nombres de consommateurs connectes...etc...pointe de debit.....acte de maintenance.
    -proprietes physique d'un node : dote de vanne,marque de vanne ,annee de fabrication etc.....

    2/Soit un GIS hydraulique
    -proprietes fonctionnelles :coord,localite,proprietaire........
    -proprietes physique d'un node : dote de vanne,marque de vanne ,annee de fabrication etc.....

    Ce qui fait que c'est l'analyse fonctionnelle de l'application-que nous n'avons pas - qui fera ressortir si on a besoin ,comme l'as dit Don Quiche, d'une classe Zone ancetre ayant des champs communs et d'une classe heritee pour chaque type.
    Dans une zone d'un type donne un Dico par type de noeud est interessant si il ya plusieurs noeuds de ce type dans la dite zone(ce que j'avais compris implicitement de ta structure).
    Sinon une reference sur le noeud support suffit(voir reservoir).

    Par ailleurs au passage ,il s'agit la d'un reseau hydraulique dit de "Transport ou ossature principale" " et non de "Distribution ou ossature raccorde directement au consommateurs finaux " c'est pour cela que la "Water Resource " dans mon esprit me semblait etre une zone geographique apparente à une zone concede ou concession en francais ou il y avait le poste principal "Reservoir" de la Company raccordes à plusieurs noeuds ordinaires de consommateurs.
    S'il s'agit de la representation d'un reseau au passage ,il manque "les arcs" ou canalisations represente par une classe paire de nodes(fromNode,ToNode) avec un dico des "Neighbours nodes" ou voisins d'un noeud.
    Tout depend donc au final de la fonctionnalite du projet d'application et des conseils d'ordre general pourraient s'averer innopportun en l'absence de plus de details de ton part......

    bon code................

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

    Merci de ne pas m'avoir laché en route

    @DOnQuiche
    Je pense avoir suivi t explications, merci. La seule chose que je n ai pas compris, c'est comment si j'utilise un seul dico (et une classe mere pour les jeux publics et une fille pour les privés), je saurais lorsque je boucle a travers toutes les clés qu'il s'agit d'un element public ou privé ? Devrais je tester que Dem est null par exemple ?

    @Mabrouki
    POur expliquer un peu plus, je travaille sur un projet de recherche qui vise a etudier l'impact du changement climatique sur la ressource en eau dans le sud-ouest de l'Angleterre et a proposer une meilleure gestion/distribution de celle-ci.
    En angleterre, la carte est divisée en zones ou les habitants sont identifiés comme ayant un meme risque (ce sont les wrz). Et les entreprises de distribution en eau se partagent ces water resources zones. Voila pourquoi une water company peut avoir plusieurs wrz.
    Etant donné que mon projet est sur tout le sud-est de l angleterre, notre modele est assez grossier. C'est a dire que si une wrz contient plusieurs reservoirs (pouvant stocker de l'eau), on considere un seul reservoir de capacité egale a la somme de tous les reservoirs de la zone. Pareil pour toutes les pertes qui sont comptabilisés dans les noeuds WTW (Water treatment Work), et pareil pour la demande en eau pour la wrz qui n est qu un noeud Dem. (Dembis et Junction sont en fait des noeuds un peu speciaux qu il serait long a expliquer ...)
    j ai biensur des liens entre ces noeuds, et l'eau peut etre transporté de zone en zone si besoin est. (C'est d ailleurs une des choses a tester ..) Mais je pense que si j arrive a avoir les idees claires sur les noeuds, je ne devrais pas avoir de problemes pour les liens ...

    QU est ce que je vais faire de ces elements ?
    En fait, afin de simuler l'ecoulement d'eau entre mes noeuds de demande et mes reservoirs, on va utiliser un programme que l'on developpe avec une université. Il s'agit d'un vieux programme que l'on depoussiere et qui est ecrit (comme bcp de vieux programmes scientifiques) en Fortran ...
    Pour fonctionner, ce programme a besoin d'avoir un certain nombre de fichiers d'entrees contenant notemment la structure du reseaux.

    Tout ce que je veux faire (en tout cas dans un premier temps), c'est pouvoir creer facilement depuis ma base de données (SQLite) les fichiers d'entrees dont mon code fortran a besoin.

    (il faut savoir que ma base de données contient environ 900 noeuds).

    Et comme je voyais bien que ma creation de classe etait bien bancale, je me suis dit que c'etait un bon exemple pour essayer de comprendre comment j'aurais pu faire les choses plus ...'proprement'/''simplement'.

    En tout cas, merci pour votre aide les gars. C cool !

    Slumpy

  10. #10
    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
    Bonsoir à toi !

    Pour le test public/privé, non, le mieux est d'avoir une propriété booléenne IsPublic. Si tu optes pour un modèle à une seule classe cette propriété pourrait s'appuyer sur la valeur de Water_Company pour déterminer le résultat. En revanche si tu optes pour un modèle à deux/trois classes, cette propriété sera surchargée pour toujours renvoyer vrai dans la classe des zones publiques, et faux dans la classe des zones privées.

    Sinon, en vitesse, ton application se contente donc de :
    * Ecrire ton réseau dans un fichier au format approprié
    * Tester si deux noeuds donnés du réseau sont connectés

    Et rien d'autre, c'est bien ça ? Par ailleurs, est-il envisageable que des changements soient nécessaires à l'avenir (modèle plus raffiné avec plusieurs réservoirs par WRZ, etc) et affecteraient-ils la structure interne des zones, notamment accentuerait-ils les différences entre zones publiques et privées ? Voire peux t-on avoir besoin de davantage de types de zones à l'avenir ?

    Enfin, s'il y a davantage de besoins fonctionnels, certains d'entre eux impliquent-ils un comportement fondamentalement différent entres zones publiques et privées ? Le test des connexions, par exemple, va seulement impliquer d'interroger deux noeuds en moins : c'est quelque chose qui est plus rapidement achevé en écrivant un seul algo avec deux tests "différent de nothing" pour Dem et Demin plutôt qu'en écrivant deux versions de l'algo.

    Je pense que tu comprends le but de toutes ces questions. Donc si quelque chose te paraît pertinent dans ce goût-là... Et de rien pour le coup de main.

  11. #11
    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 nodes et arcs
    bonjour Sumpy
    En fait Slumpy s'agissant d'un reseau (network) ,un petit detour du cote de la modelisation d'un reseau implemente comme un graphe me semble necessaire.
    On ne peut modeliser valablement un tel reseau que par une vue d'ensemble noeud et arcs.
    Dans un graphe la modelisation la plus efficace est faite par une matrice d'adjacence arc-noeud ,c.à.d que la description complete du reseau se fait à partir de la liste des Arcs ou Liens(fromNode,ToNode ou en francais Noeud Amont-Noeud Aval).
    Quand à la distinction des zones en public ou privees,si je te suis depuis le debut c'est plutot Injector Zone (public =fonction Injecteur) et Demand Zone (privees=fonction demande de charge).
    S'agissant des zones Dembis et Junction c'est pas plutot Fictif Zone ("fictious node"=necessite par la structure du reseau c.à.d des liens) .Des noeuds qui ne ne stocke physiquement rien et sont des noeuds de transit(vanne,te etc.... ).
    Mais au final les noeuds de la bd(en vrac) seront modelises par des types noeuds personnalisees adapte à l'application.
    bon code......

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

    @DonQuicheEffectivement mon code va servir principalement a ecrire mon reseau dans un format approprié. Mais aussi a modifier rapidement certains parametres de mon reseau et regenerer les fichiers d'entree.

    , est-il envisageable que des changements soient nécessaires à l'avenir (modèle plus raffiné avec plusieurs réservoirs par WRZ, etc) et affecteraient-ils la structure interne des zones, notamment accentuerait-ils les différences entre zones publiques et privées ? Voire peux t-on avoir besoin de davantage de types de zones à l'avenir ?
    Il s'agit d'un projet de recherche qui va continuer pour encore 1an et demi, donc oui potentiellement des changements pourraient s'averer etre necessaires. Par par exemple avoir plusieurs reservoirs dans une wrz oui, mais avoir d'autres types de zones j en doute. Etant donné que la grande difference entre ce que tu appelles les zones privés et publiques est tout simplement que l'une represente une zone geographique (wrz) alors que l'autre correspond à un element bien precis (un reservoir qui peut approvisionner plusieurs zones). Donc je vois pas trop quelle autre type je pourrais avoir besoin.

    @Mabrouki
    J avoue que je ne suis pas sur de te suivre.
    Mais pour info (si tu fais allusion a cela), je n'ai pas crée mon reseau en remplissant une base de donné. En fait, une université anglaise à developpé un outil graphique permettant de visualiser des shapefiles (donc voir ou sont les sources, les reservoirs, les WTW) et de dessiner les liens. Le programme se charge de generer la base SQLite que je suis entrain de manipuler.

    En ce qui concerne ton interpretation des zones privés et publiques.Les deux types de zones recoivent de l'eau des sources qui remplissent leur reservoir. Maintenant, le reservoir d'une WRZ sert à satisfaire la demande en eau de la zone, alors que le reservoir de la zone privé sert uniquement à reremplir le reservoir de la zone publique, si celui-ci ne peut pas revenir a son niveau normal grace a ce qui peut etre pompé de ses propres sources. (voila d'ailleurs pourquoi une zone privé n a pas de Dem et Dembis)

    Et ce que c'est ce que tu avais en tete ?


    Etat actuel du code
    voila l'etat actuel de la subroutine principal :
    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
    SQLcommand1.CommandText = "SELECT * FROM nodes where (RWSM_type==""WRZ Reservoir"" or RWSM_type==""WRZ WTW"" or RWSM_type==""WRZ Junction"" or RWSM_type==""WRZ Dembis"" or RWSM_type==""WRZ Dem"" or RWSM_type==""Spec Reservoir"" or RWSM_type==""Spec WTW"" or RWSM_type==""Spec Junction"")"
     
     
            Dim SQLreader1 As SQLiteDataReader = SQLcommand1.ExecuteReader()
            While SQLreader1.Read()
                Dim Anode As New My_node(SQLreader1)
                Dico_nodes.Add(Anode.node_id, Anode)
     
                Dim aSet As My_Set
                If Dico_Set.ContainsKey(Anode.WRZ) = False Then
                    'nouvelle zone
                    aSet = New My_Set(Anode)
                    Dico_Set.Add(aSet.WRZ, aSet)
                End If
                aSet = Dico_Set(Anode.WRZ)
     
                Select Case Anode.RWSM_type
                    Case My_node.NodeType.Reservoir
                        Dim objReservoir As New My_Reservoir(Anode)
                        aSet.Reservoir = objReservoir
                    Case My_node.NodeType.WTW
                        Dim objWTW As New My_WTW(Anode)
                        aSet.WTW = objWTW
                    Case My_node.NodeType.Junction
                        aSet.Junction = Anode
                    Case My_node.NodeType.Dembis
                        aSet.Dembis = Anode
                    Case My_node.NodeType.Dem
                        aSet.Dem = Anode
                End Select
     
     
     
            End While
            SQLreader1.Close()
     
     
     
            For Each awrz As String In Dico_Set.Keys
                Console.WriteLine()
                Console.WriteLine()
                Console.WriteLine(awrz)
                Console.WriteLine(Dico_Set(awrz).Is_a_WRZ)
                Console.WriteLine(Dico_Set(awrz).Reservoir.RefNode.node_id & vbTab & Dico_Set(awrz).Reservoir.RefNode.name & vbTab & Dico_Set(awrz).Reservoir.Capacity)
                Console.WriteLine(Dico_Set(awrz).WTW.RefNode.node_id & vbTab & Dico_Set(awrz).WTW.RefNode.name)
                If Dico_Set(awrz).Is_a_WRZ Then
                    Console.WriteLine(Dico_Set(awrz).Dem.node_id & vbTab & Dico_Set(awrz).Dem.name)
                    Console.WriteLine(Dico_Set(awrz).Dembis.node_id & vbTab & Dico_Set(awrz).Dembis.name)
                End If
            Next
     
        End Sub
    End Class
    Avec mes differents noeuds :
    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
    Imports System.Data.SQLite
     
    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 NodeType
     
        Enum NodeType
            Reservoir = 1
            WTW = 2
            Junction = 3
            Dembis = 4
            Dem = 5
        End Enum
     
     
        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)
            If IsDBNull(SQLreader(7)) = False Then
                Me.Water_company = SQLreader(7)
            End If
            Me.WRZ = SQLreader(8)
            Select Case SQLreader(9)
                Case "WRZ Reservoir", "Spec Reservoir"
                    Me.RWSM_type = NodeType.Reservoir
     
                Case "WRZ WTW", "Spec WTW"
                    Me.RWSM_type = NodeType.WTW
     
                Case "WRZ Junction", "Spec Junction"
                    Me.RWSM_type = NodeType.Junction
     
                Case "WRZ Dembis"
                    Me.RWSM_type = NodeType.Dembis
     
                Case "WRZ Dem"
                    Me.RWSM_type = NodeType.Dem
     
                Case Else
                    Console.WriteLine("ERRRROOOOOR")
            End Select
        End Sub
     
    End Class
     
     
    Public Class My_Reservoir
        Public Capacity As Integer
        Public Initial_Storage As Integer
        Private m_refnode As My_node            'prop avec reference sur noeud support
     
        Public Sub New(ByVal objNode As My_node)
            Me.m_refnode = objNode
        End Sub
     
        Public Property RefNode() As My_node
            Get
                Return m_refnode
            End Get
            Set(ByVal value As My_node)
                m_refnode = value
            End Set
        End Property
     
    End Class
     
    Public Class My_WTW
        Public Losses As Double
        Private m_refnode As My_node            'prop avec reference sur noeud support
     
        Public Sub New(ByVal objNode As My_node)
            Me.m_refnode = objNode
        End Sub
     
        Public Property RefNode() As My_node
            Get
                Return m_refnode
            End Get
            Set(ByVal value As My_node)
                m_refnode = value
            End Set
        End Property
     
    End Class
    Et ma nouvelle classe My_Set qui remplasse My_WRZ etant donné que cette classe est commune aux deux et represente just un Set de noeuds.
    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
    Public Class My_Set
        Public Water_company As String
        Public WRZ As String
        Public Reservoir As My_Reservoir            'Dictionary(Of String, My_Reservoir)
        Public WTW As My_WTW                        'Dictionary(Of String, My_node)
        Public Junction As My_node                  'Dictionary(Of String, My_node)
        Private m_dembis As My_node                 'Dictionary(Of String, My_node)
        Private m_dem As My_node                    'Dictionary(Of String, My_node)
        Public Is_a_WRZ As Boolean
     
     
        Public Sub New(ByVal anode As My_node)
            Me.WRZ = anode.WRZ
     
            If IsDBNull(anode.Water_company) Then
                Me.Is_a_WRZ = False
            Else
                Me.Is_a_WRZ = True
                Me.Water_company = anode.Water_company
            End If
        End Sub
     
        Public Property Dembis() As My_node
            Get
                'If Me.Is_a_WRZ = True Then
                Return m_dembis
                'End If
            End Get
            Set(ByVal value As My_node)
                If Me.Is_a_WRZ = True Then
                    m_dembis = value
                End If
            End Set
        End Property
     
        Public Property Dem() As My_node
            Get
                If Me.Is_a_WRZ = True Then
                    Return m_dem
                Else
                    Return Nothing
                End If
            End Get
            Set(ByVal value As My_node)
                If Me.Is_a_WRZ = True Then
                    m_dem = value
                End If
            End Set
        End Property
     
    End Class

    J'espere que je simplifie la chose plutot que de la compliquer inutilement ...

    Merci

    Slumpy

  13. #13
    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
    Au vu de tout ce que tu nous as dit, un modèle à deux ou trois classes semble être la meilleure chose à faire. En tout honnêteté nous progressons un peu dans l'ombre parce que nous avons du mal à te faire comprendre ce que nous voulons mais ce modèle à deux classes semble un bon pari. Voilà une proposition, n'hésite pas à l'adapter à tes goûts. Note l'usage des propriétés automatiques, qui font gagner du temps : elles créent automatiquement les champs sous-jacents et ne prennent qu'une ligne. Du coup, nous n'avons pas besoin de déclarer un seul champ dans Zone.

    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
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    Public Class Zone
       Property ID As String 'Remplace WRZ
       Property Name As String 
       Property Company As String
     
       Property Wtw As WtwNode
       Property Reservoir As ReservoirNode
       Property Junction As Node
     
       Public Sub New(reader As SQLiteDataReader)
          ' Code de lecture
       End Sub
     
       Public Overridable ReadOnly Property IsPublic() As Boolean
    	Get
       	   Return True
    	End Get
       End Property
     
       Public Overridable Property Dem() As Node
    	Get
       	   Return Nothing
    	End Get
    	Set
    	   Throw New InvalidOperationException()
    	End Set
       End Property
     
       Public Overridable Property Dembis() As Node
    	Get
    	   Return Nothing
    	End Get
    	Set
    	   Throw New InvalidOperationException()
    	End Set
       End Property
    End Class


    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
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    Public Class PrivateZone Inherits Zone
       Private _dem As Node
       Private _dembis As Node
     
       Public Sub New(reader As SQLiteDataReader)
     	MyBase.New(reader)
            ' Code de lecture
       End Sub
     
       Public Overrides ReadOnly Property IsPublic() As Boolean
    	Get
    	   Return False
    	End Get
       End Property
     
       Public Overrides Property Dem() As Node
    	Get
    	   Return _dem
    	End Get
    	Set
    	   _dem = value
    	End Set
       End Property
     
       Public Overrides Property Dembis() As Node
    	Get
    	   Return _dembis
    	End Get
    	Set
    	   _dembis = value
    	End Set
       End Property
    End Class


    PS : Si tu prends ce modèle, quand tu étendras tes classes, songe au Dependency Inversion Principle : essaie de faire faire le boulot par les noeuds ou les zones elles-mêmes plutôt que par des classes d'un niveau supérieur. Par exemple, pour l'export des données, il est plus judicieux d'avoir sur ta zone une méthode Export qui se charge de l'écrire au format correspondant dans le flux passé en argument, plutôt que d'avoir une grande méthode Export sur une classe de plus haut niveau qui lirait les propriétés des zones pour écrire le fichier. Sans cela, ce modèle à deux classes perd de son intérêt.

    PPS : Tu avais parlé d'assigner une valeur à CompanyZone pour les zones publiques. Si c'est la même valeur pour toutes les zones publiques, alors il vaudrait mieux lui appliquer le même traitement qu'à Dem et Dembis : on renvoie une valeur constante pour les zones publiques et on surcharge pour renvoyer la valeur d'une variable pour les zones privées.

    PPPS : J'ai défini toutes les propriétés comme read/write mais plusieurs d'entre elles ne sont vraisemblablement assignées que par l'instance elle-même, dans le constructeur. Si c'est le cas, il n'y a aucun problème à ne faire que des propriétés read-only (par contre, en VB on ne peut pas faire ça avec des propriétés automatiques ; en C# on pourrait définir une accessibilité privée pour le setter - VB c'est le mal).

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