Bonjour :-)

Je viens avec une question de design. Le but du code que nous développons (open source, c'est beau, hein ?) est de modéliser des systèmes physiques particuliers. On va devoir reproduire le comportement de quatre entités de base - des lignes - et elles devront être gérés par des classes adaptées. Mais certaines d'entre elles auront des morceaux d'algorithmes identiques, d'autres non.
il y aura des fonctions type operator ==, mais renvoyant parfois des tribool, et qui dépendront du type de ligne à traiter. Tous ces objets lignes sont contenus dans des graph, conteneurs doués de certaines fonctions ad-hoc, et différentes classes peuvent travailler sur ces graphes.

Pour le moment, je fais un petit démonstrateur de la solution envisagée, à base d'object factory et d'abstract factory, mais c'est surtout l'organisation en classe qui me fait souci. Ci-dessous un petit bout de code.
Pour résumer : les lignes dérivent d'une classe BaseLine, et ajoutent des données membres suivant leur type physique, sur lesquelles pourront porter des opérations spécifiques.
les graph suivent des types analogues, mais possèdent tous un même conteneur vers une liste de BaseLine* (a priori pas trop le choix, parce que les lignes seront créées par l'abstract factory et sauf erreur de ma part, il faut bien que les objets line qui en sortent dérivent du même type de base, non ?)
Ce qui me chiffonne c'est que je me trouve contraint de faire du static_cast dans le graph dérivé du graph de base pour faire appelle aux propriétés spécifiques des lignes dérivées... est-ce logique ?
Y a-t-il une astuce pour les fonctions coincide, autre que de les mettre dans des namespace pour pouvoir appeler la bonne au sein des différentes classes ?
Pour les différentes classes qui vont travailler sur graph suivant son type - et donc le type des lignes - on risque d'avoir des problèmes analogues... ce qui me fait me demander si notre approche est saine ?

Voili voilou, si vous avez des suggestions, je suis carrément preneur !

Merci beaucoup :-)

Hugo/Marc








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
#include <iostream>
#include<list>
#include<boost/foreach.hpp>
 
using namespace std;
 
//=============================================
//Les classes lines
//=>une base et deux dérivées
//=============================================
 
//classe de base
class BaseLine{
    public:
    virtual void Action();
    unsigned GetTag(){return _tag;}
 
    BaseLine(unsigned t):_tag(t){}
    virtual ~BaseLine(){}
 
    protected:
    unsigned _tag;
};
void BaseLine::Action(){cout << "Action de BaseLine avec tag : " << _tag << endl; }
 
//première classe dérivée
class PlaneLine : public BaseLine{
 
    public:
    PlaneLine(unsigned t, int p):BaseLine(t),_plane(p){}
    int GetPlane(){return _plane;}
    void Action();
 
    private:
    int _plane;
 
};
void PlaneLine::Action(){cout << "Action de PlaneLine avec tag : " << _tag << " et plane : "<<_plane << endl;}
 
//deuxième classe dérivée
class FaultedLine : public BaseLine{
    public:
    FaultedLine(unsigned t, int p, int f):BaseLine(t),_plane(p),_fault(f){}
    ~FaultedLine(){}
    void Action();
 
    private:
    int _plane;
    int _fault;
};
void FaultedLine::Action(){cout << "Action de FaultedLine avec tag : " << _tag << ", plane : "<<_plane <<" et faute : "<< _fault << endl;}
 
//==============================================
//Les classes graph : une base et deux dérivées
//==============================================
 
//===================
//la classe de base 
//===================
 
class GraphBase{
 
public:
//interface et constructeur
virtual void Action();
 
virtual ~GraphBase()
{
    BOOST_FOREACH(BaseLine* l,_lines)
       delete l;
}
GraphBase(unsigned t):_tag(t){}
void PushLine(BaseLine* l){_lines.push_back(l);}
 
protected:
 
//quelques algo communs à tout le monde
 
void MethodeElem1();
void MethodeElem2(BaseLine* line);
 
unsigned _tag;
list<BaseLine*> _lines;
};
 
void GraphBase::MethodeElem1()
{
    cout << "Méthode élém 1 de GraphBase" << endl;
    BOOST_FOREACH(BaseLine* l,_lines)
       l->Action();
}
 
void GraphBase::MethodeElem2(BaseLine* line)
{
    cout <<" MéthodeElem2 de la classe GraphBase" << endl;
    cout << " sur la ligne : " << line->GetTag() << endl;
}
 
void GraphBase::Action()
{
    cout << "Action de GraphBase - tag : "<<_tag << endl;
    MethodeElem1();
    BOOST_FOREACH(BaseLine* l,_lines)
      MethodeElem2(l);
}
 
 
//=====================
//la classe GraphPlane
//=====================
class GraphPlane: public GraphBase
{
    public :
    GraphPlane(unsigned t):GraphBase(t){}
    void Action();
 
    private:
    void AlgoSpecPlane();
};
 
void GraphPlane::AlgoSpecPlane()
{
    cout << "GraphPlane::AlgoSpecPlane du graph # " << _tag << endl;
    BOOST_FOREACH(BaseLine* pl,_lines)
      cout << "line #" << static_cast<PlaneLine*>(pl)->GetTag() << " Plane # " << static_cast<PlaneLine*>(pl)->GetPlane() << endl;
}
 
void GraphPlane::Action()
{
    cout << "Action de GraphPlane Graph # " << _tag << endl;
    AlgoSpecPlane();
    MethodeElem1();
}
 
 
 
int main()
{
    //on crée deux graph
    GraphBase* gb = new GraphBase(0);
    GraphBase* gp = new GraphPlane(1);
 
    //on crée des lignes de base
    BaseLine* bl0 = new BaseLine(0);
    BaseLine* bl1 = new BaseLine(1);
    BaseLine* bl2 = new BaseLine(2);
    BaseLine* bl3 = new BaseLine(3);
    //on crée des lignes avec plan
    BaseLine* pl0 = new PlaneLine(0,-1);
    BaseLine* pl1 = new PlaneLine(1,1);
    BaseLine* pl2 = new PlaneLine(2,1);
    BaseLine* pl3 = new PlaneLine(3,-1);
 
    //on stocke tout ce petit monde où c'est logique
    gb->PushLine(bl0);gb->PushLine(bl1);gb->PushLine(bl2);gb->PushLine(bl3);
    gp->PushLine(pl0);gp->PushLine(pl1);gp->PushLine(pl2);gp->PushLine(pl3);
 
    gb->Action();
    gp->Action();
 
    return 1;
}