Bonjour,

Je travaille sur un projet dans l'embarqué et je fait face à un problème de "Dual Inheritance Hierarchies".

J'ai un premier composant logiciel dont le rôle est de transformer un flot d'octets reçu depuis une interface matérielle en objets de type "Requetes". J'utilise un pattern fabrique abstraite dans ce composant et j'obtient une première hierarchie d'objet : la classe de base IRequete (abstraite) et un ensemble de classes de CRequete_X,Y,Z hérités de IRequete et permettant d'instancier les objets obtenus après désérialisation du flux d'octets. Ce composant n'a pas vocation à connaitre la nature des traitements qui seront effectués concernant ces requêtes.

J'ai ensuite plusieurs composants dont le rôle va être de traiter ces requetes. Mon premier composant (celui qui crée les objets "requete") fournit un service permettant de venir enregistrer des commandes (ICommande asbtraite) à associer à un objet de type IRequete par rapport à un identifiant (cf code fourni,methode => RegisterCommand).

Je trouve donc une deuxième hierarchie d'objets (les commandes) donc la classe de base (ICommande) définit le comportement (1 méthode Execute virtuelle pure + 1 paramètre de type IRequete) et les classes dérivées définissent concrètement le traitement à exécuter.

Mon problème est qu'au final pour associer un objet de type CRequete_X de la hierarchie IRequete à une commande CCommande_X de la hierarchie ICommande, je suis obligé de passer par un downcast.

Quelqu'un aurait-il une solution plus élégante et différente d'une utilisation du pattern Visiteur?

J'ai fourni un exemple de code illustrant mon implémentation actuelle.

Merci
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
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
#include <iostream>
using namespace std;

static const unsigned char C_MAX_ID = 5; 

// REMARQUE : TOUTES LES METHODES ONT ETE INLINEES POUR L'EXEMPLE.

// ==== CLASSE DE BASE DES REQUETES ===========
class IRequete
{
public:
	virtual ~IRequete(){}
	unsigned char GetId() const {return(_identifiant);}
protected:
	IRequete(const unsigned char id):_identifiant(id){}
	unsigned char _identifiant;
};


// ==== CLASSES DERIVEES DES REQUETES ===========
class CRequeteX:public IRequete
{
public:
	// constructeur avec parametres arbitraires pour example
	CRequeteX():IRequete(0),_param1(101),_param2(102){}
	virtual ~CRequeteX(){}

	// Accesseurs
	unsigned char GetParam1() const{ return(_param1);}
	unsigned char GetParam2() const{ return(_param2);}

private:
	unsigned char _param1;
	unsigned char _param2;
};

class CRequeteY:public IRequete
{
public:
	// constructeur avec parametres arbitraires pour exemple
	CRequeteY():IRequete(1),_param1(101),_param2(102),_param3(103),_param4(104){}
	virtual ~CRequeteY(){}

	// Accesseurs
	unsigned char GetParam1() const{ return(_param1);}
	unsigned char GetParam2() const{ return(_param2);}
	unsigned char GetParam3() const{ return(_param3);}
	unsigned char GetParam4() const{ return(_param4);}

private:
	unsigned char _param1;
	unsigned char _param2;
	unsigned char _param3;
	unsigned char _param4;
};


// ==== CLASSES DE BASE DES COMMANDES ===========
class ICommande
{
public:
	virtual ~ICommande(){}
	virtual void Execute() = 0;

	void SetParam(IRequete& refRequeteObj) { _RequeteParametre = &refRequeteObj;} 

protected:
	IRequete* _RequeteParametre;
};


// ==== CLASSES DERIVEES DES COMMANDES ===========
class CCommandeX:public ICommande
{
public:
	// Constructeur/Destructeur
	CCommandeX(){}
	virtual ~CCommandeX(){}

	virtual void Execute() {
		cout << "CCommandeX execute" << endl;
		// Downcast (static / en embarqué contraint par le temps de les faire dynamiques)
		// A proscrire pour les puristes !!!!!!!
		CRequeteX& requeteObj =  static_cast<CRequeteX&>(*_RequeteParametre);
		// Traitement personnalisé de la requête : ici example, on affiche juste
		// les parametres
		cout << requeteObj.GetParam1()<< endl;
		cout << requeteObj.GetParam2()<< endl;
	}
};

class CCommandeY:public ICommande
{
public:
	// Constructeur/Destructeur
	CCommandeY(){}
	virtual ~CCommandeY(){}

	virtual void Execute() {
		cout << "CCommandeY execute" << endl;
		// Downcast (static / en embarqué contraint par le temps de les faire dynamiques)
		// A proscrire pour les puristes !!!!!!!
		CRequeteY& requeteObj =  static_cast<CRequeteY&>(*_RequeteParametre);
		// Traitement personnalisé de la requête : ici exemple, on affiche juste
		// les parametres
		cout << requeteObj.GetParam1()<< endl;
		cout << requeteObj.GetParam2()<< endl;
		cout << requeteObj.GetParam3()<< endl;
		cout << requeteObj.GetParam4()<< endl;
	}
};


// ==== CLASSES DE GESTION DE L'ARRIVEE DES REQUETES : SIMPLIFIEE POUR l'EXAMPLE ===========
class CInterfaceController
{
public:
	// Singleton
	static CInterfaceController& GetInstance() { return(_sInstance);}
	static void ReleaseInstance() { /* static instance */}

	// Association Commande/Requete
	void RegisterCommand(const unsigned char idRequete,ICommande& refCommande){
		// pour simplifier pour l'exemple idRequete = id table
		tableCommandes[idRequete] = &refCommande;
	}

	// ======= JUSTE POUR L'EXAMPLE =================
	// Example simplifié de création d'un objet requete et d'execution de la commande associée
	void ExampleReceptionRequeteX()
	{
		// Requete 
		CRequeteX& requete = *new CRequeteX;
		unsigned char id = requete.GetId();

		// Preparation & Execution Commande sous sa forme abstraite
		ICommande* commandeAssociee = tableCommandes[id];
		commandeAssociee->SetParam(requete);
		commandeAssociee->Execute();
		
	}
	void ExampleReceptionRequeteY()
	{
		// Requete 
		CRequeteY& requete = *new CRequeteY;
		unsigned char id = requete.GetId();

		// Preparation & Execution Commande sous sa forme abstraite
		ICommande* commandeAssociee = tableCommandes[id];
		commandeAssociee->SetParam(requete);
		commandeAssociee->Execute();
	}

	// Destructeur
	~CInterfaceController(){}

private:
	// static instance
	static CInterfaceController _sInstance;

	// Constructeur/Destructeur
	CInterfaceController(){}

	// Association command request
	ICommande* tableCommandes[C_MAX_ID];

};

CInterfaceController CInterfaceController::_sInstance;


// ================ TEST =========================
void main()
{
	// Creation des commandes
	CCommandeX& cmdX =  *new CCommandeX;
	CCommandeY& cmdY =  *new CCommandeY;

	// Enregitrement des commandes
	CInterfaceController::GetInstance().RegisterCommand(0,cmdX);
	CInterfaceController::GetInstance().RegisterCommand(1,cmdY);

	// Simulation de la reception de 2 requete X & Y
	CInterfaceController::GetInstance().ExampleReceptionRequeteX();
	CInterfaceController::GetInstance().ExampleReceptionRequeteY();
}