Bonjour,
J'aurais une question d'architecture générale sur le C++.
La question porte sur qu'elle est le meilleur moyen d'ajouter des fonctionnalités à une classe C++.
Plus précisément, est qu'il existe un moyen de faire une "union" de classes dans le sens de faire une union de leurs méthodes ?
Je vais illustrer ma question sur un exemple très simple.
Imaginons que l'on est une classe "Tab" représentant un tableau creux.
Cette classe contient des structures de données permettant de modéliser l'objet et quelques méthodes permettant de le manipuler.
Voici une implémentation très naïve (par souci de simplicité) de la classe Tab :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| class Tab {
public:
Tab() {
}
void set(int x, int val) {
tab.push_back( make_tuple(x, val));
}
int get() {
// ...
}
private:
vector< pair<int, int> > tab;
}; |
Imaginons que l'on souhaite implémenter une fonctionnalité pour cette classe.
Par exemple obtenir la moyenne des éléments du tableau.
Plusieurs possibilités s'offre à nous :
1> Modifier la classe : on ajoute dans la classe des attribues, et chaque fois qu'on l'on fait un "set", on met a jour ses attributs.
Cette méthode à plusieurs inconvenants :
- On alourdit la classe
- Même si l'on n'utilise pas la fonctionnalité getMoy, des calculs seront effectués chaque fois que l'on fait un "set"
2> Créer une fonction : on créer une fonction qui prend en argument Tab puis calcule et renvoi la moyenne.
Cette méthode a plusieurs inconvenants :
- Les calculs ne se font pas de manière itérative (pas forcément gênant pour cet exemple, mais on peut imaginer des cas ou ceci est un problème)
- On n'a pas d'attribut lié à l'objet nous permettant des garder certaines informations. Pour cet exemple, on ne sauvegarde pas la valeur de la moyenne, donc chaque fois que l'on fait appelle à getMoy, on doit tout recalculer.
3> Héritage : on créer une classe TabWithMoy qui ajoute ce dont a besoin pour calculer la moyenne.
Inconvénients :
- Très lourd et lent.
- Si l'on souhaite ajouter plusieurs fonctionnalités, on doit créer une chaine d'héritage (beurk !)
4> Héritage 2 : Utiliser le design pattern "composite"
Inconvénients :
- Lenteurs dues à l'héritage
5> Algorithme en attribut : on créer une classe qui contient la structure de donné "Tab" et tous les algorithmes dont on a besoin
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| class TabWithSomeAlgo {
Tab tab;
Moy moy;
void set(int x, int val) {
tab.set(int x, int val);
moy.set(int x, int val);
}
double getMoy() {
return moy.getMoy();
}
int get(int x) {
tab.get(x);
}
} |
Cette solution me semble être la meilleure, mais elle a encore quelques défauts.
Chaque fois que l'on souhaite ajouter une nouvelle fonctionnalité, on doit modifier la classe "TabWithSomeAlgo" à plusieurs endroits :
- On ajoute un attribut pour la nouvelle fonctionnalité, ET on doit faire appel à ce nouvel attribut dans toutes les méthodes qui sont également présentes dans ce nouvel attribut.
Existe-t-il une astuce permettant de faire appel à ces méthodes de manière automatique ?
Un truc du type
typedef class_union<Tab, Moy> TabWithSomeAlgo;
De telle sorte que lorsque l'on fait appel à une méthode de TabWithSomeAlgo, cela fasse également appelle à cette même méthode pour tous les objets qui ont également cette méthode.
Théoriquement, le compilateur a toutes les informations nécessaires pour pouvoir faire ça, mais est-ce que cela est possible à implémenter ?
Si quelqu'un a une idée ou des remarques là-dessus ?
Merci
Partager