1

Salut, un problème que je rencontre souvent, je me demande s’il n’y a pas une façon élégante de le gérer.

Imaginons que l’on veuille modéliser des véhicules (bon l’exemple ne sera pas forcément très cohérent, mais c’est juste pour représenter un genre de situation que je rencontre assez souvent), dont on s’intéresse à la vitesse moyenne, par exemple. On veut pouvoir modéliser un vélo et une moto. Concernant le vélo, on s’intéresse (entre autres) au nombre de pignons et de plateaux dont il dispose, et pour la moto, on veut pouvoir savoir quel carburant elle utilise.
Ce qui peut nous conduire, par exemple à une modélisation de ce type :
RLJc
Je n’ai mis que quelques données, pour réduire mon problème à l’essentiel.

Avec cette modélisation, un objet qui traite un ensemble de véhicules pourra recevoir des motos ou des vélos, et appliquer dessus tout ce qui est visible au niveau de l’interface publique de Véhicule (on pourrait par exemple accéder à leur vitesse moyenne), mais on n’a aucun moyen de bénéficier des informations spécifiques aux classes filles (Moto et Vélo). À moins de faire de l’introspection, mais ça ne m’intéresse pas car je devrai modifier les classes utilisant des véhicules à chaque fois que j’ajouterai une spécialisation.

Connaissez-vous des solutions élégantes pour gérer ce type de problèmes ?
avatar
« Quand le dernier arbre sera abattu, la dernière rivière empoisonnée, le dernier poisson capturé, alors vous découvrirez que l'argent ne se mange pas. »

2

Moto *moto = qobject_cast<Moto *>(vehicule);
if (moto) {
  qDebug("%s", moto->carburant.toLocal8Bit().data());
} else {
  Velo *velo = qobject_cast<Velo *>(vehicule);
  if (velo) {
    qDebug("%d %d", velo->nb_pignons, velo->nb_plateaux);
  }
}

N'importe quel système de RTTI (aussi dynamic_cast en C++ avec le RTTI par défaut, instanceof en Java etc.) permet ce fonctionnement.
avatar
Mes news pour calculatrices TI: Ti-Gen
Mes projets PC pour calculatrices TI: TIGCC, CalcForge (CalcForgeLP, Emu-TIGCC)
Mes chans IRC: #tigcc et #inspired sur irc.freequest.net (UTF-8)

Liberté, Égalité, Fraternité

3

Sasume (./1) :
À moins de faire de l’introspection, mais ça ne m’intéresse pas car je devrai modifier les classes utilisant des véhicules à chaque fois que j’ajouterai une spécialisation.

L’utilisation de RTTI est ce que je désignais par introspection (mais peut-être que le terme est incorrect, je ne sais pas trop).
En fait j’aimerais justement savoir s’il est possible de se passer de RTTI. J’ai bien une ou deux idées, mais avant de réinventer la roue (qui risque pas mal d’être carrée si c’est moi qui le fait) je sonde pour voir s’il n’y a pas des solutions types éprouvées pour résouder ce genre de problèmes.
avatar
« Quand le dernier arbre sera abattu, la dernière rivière empoisonnée, le dernier poisson capturé, alors vous découvrirez que l'argent ne se mange pas. »

4

icule {   Q_OBJECT   public:     int nb_pignons, nb_plateaux; }; void Vehicule::debug_output() {   Moto *moto = qobject_cast<Moto *>(this);   if (moto) {     qDebug("%s", moto->carburant.toLocal8Bit().data());   } else {     Velo *velo = qobject_cast<Velo *>(this);     if (velo) {       qDebug("%d %d", velo->nb_pignons, velo->nb_plateaux);     }   } }Bah, l'alternative, c'est d'avoir une méthode virtuelle dans la classe Véhicule qui fait le boulot, après c'est pour l'ajout d'une méthode qu'il faut tout modifier. Il y a aussi des bidouilles comme le visitor pattern qui peuvent aider. Ou sinon, une solution (bidouille, il faut le dire) comme ça (l'exemple est encore en Qt parce que c'est ce que je connais le mieux):class Vehicule {   Q_OBJECT   public:     int vitesse_moyenne;     void debug_output(); }; class Moto : public Vehicule {   Q_OBJECT   public:     QString carburant; }; class Velo : public Veh
(L'avantage de cette solution est qu'il y a un seul endroit à modifier si on ajoute une classe (la classe Véhicule) et de même si on ajoute une méthode.)
avatar
Mes news pour calculatrices TI: Ti-Gen
Mes projets PC pour calculatrices TI: TIGCC, CalcForge (CalcForgeLP, Emu-TIGCC)
Mes chans IRC: #tigcc et #inspired sur irc.freequest.net (UTF-8)

Liberté, Égalité, Fraternité

5

Est-ce que tu as un ou plusieurs exemples précis dans lequel tu voudrais accéder à des informations propres à une moto ou une voiture depuis une méthode générique qui traite des véhicules ? A priori, j'aurais tendance à penser que si ta méthode générique qui traite les véhicule existe et qu'elle peut avoir à traiter des informations d'une auto et d'une moto, ces informations doivent elles aussi s'apparenter à un même concept générique de même niveau que "véhicule". Ça impliquerait la possibilité de définir une interface commune et de traiter les attributs spécialisés de ton auto et de ta moto dans leurs classes mères respectives, au lieu d'essayer d'y accéder depuis "Véhicule".

Pour faire plus court, c'est difficile de s'avancer sans savoir ce que tu veux faire exactement, mais j'ai l'impression qu'il y a un souci au niveau de la modélisation (être obligé d'utiliser des dynamic_cast pour s'en sortir, c'est souvent mauvais signe).
avatar
All right. Keep doing whatever it is you think you're doing.
------------------------------------------
Besoin d'aide sur le site ? Essayez par ici :)

6

Zephyr (./5) :
A priori, j'aurais tendance à penser que si ta méthode générique qui traite les véhicule existe et qu'elle peut avoir à traiter des informations d'une auto et d'une moto, ces informations doivent elles aussi s'apparenter à un même concept générique de même niveau que "véhicule".
Exactement. Je vais réfléchir à ce que je veux pouvoir savoir d’un « Véhicule » pour voir comment gérer ça dans une interface commune.
avatar
« Quand le dernier arbre sera abattu, la dernière rivière empoisonnée, le dernier poisson capturé, alors vous découvrirez que l'argent ne se mange pas. »

7

Le design pattern Visitor peut correspondre à ton problème ? Et encore vu le problème ça ressemblera plus à un pattern Visitor hybride avec le pattern Composite ?
avatar
la Nature nous montre seulement la queue du lion. Mais je suis certain que le lion a qui elle appartient pense qu'il ne peut pas se révéler en une fois en raison de son immense taille.

- Fondateur de Ti-Gen -: http://www.tigen.org

- Membre du Groupe Orage Studio -: http://oragestudio.free.fr/

- Mon site perso -: http://tisofts.free.fr

Projets TI68K en cours:
GFA-Basic = http://www.tigen.org/gfabasic
Arkanoid.
PolySnd 3.0.

8

À mon avis le pattern visitor n'est pas du tout adapté à ce problème, mais au moins j'ai une idée de la façon dont tu aurais été tenté de l'utiliser. Par contre le pattern composite, je vois vraiment pas ce que tu pourrais faire avec ici ?
avatar
All right. Keep doing whatever it is you think you're doing.
------------------------------------------
Besoin d'aide sur le site ? Essayez par ici :)

9

Je vois plus ici le composite comme l'interface dont fait part Sasume. L'interface est composée de véhicules. Via composite elle peut déterminer le type d'un objet via une méthode descriptif (type d'objet, nom, identifiant ou autre). Les véhicules ont forcément des composants communs. Ainsi, la moto possède un réservoir d'essence tout comme la voiture mais pas le vélo. Un vélo possède des composants propres qui sont les pignons et les plateaux...
Bref mon explication n'est pas claire mais pour ma part je décomposerais le problème en composants. Connaissant les composants formant un objet, je pourrais déterminer son type (voiture, moto, vélo). Pour moi le problème a été pris à l'envers. On est partie d'un type abstrait (véhicule, vélo) vers du fonctionnel (pignons, vitesse, essence...).
Les caractéristiques d'un type d'objet (voiture, moto, vélo) n'ont pas forcément a être modélisé sous forme de classe, on peut tout simplement utilisé un fichier de description dans un format XML ou autre.
Pour conclure, le type d'un objet (voiture, vélo...) est construit de façon dynamique à l'exécution du programme par assemblage de composants plus ou moins spécifiques.
Mais encore faut-il avoir une hiérarchie de composants et d'objets importantes pour répondre au problème. Si il y a que 3 ou 4 classes, ça ne sert à rien de modéliser de cette façon. smile
Tout dépend donc du problème.
avatar
la Nature nous montre seulement la queue du lion. Mais je suis certain que le lion a qui elle appartient pense qu'il ne peut pas se révéler en une fois en raison de son immense taille.

- Fondateur de Ti-Gen -: http://www.tigen.org

- Membre du Groupe Orage Studio -: http://oragestudio.free.fr/

- Mon site perso -: http://tisofts.free.fr

Projets TI68K en cours:
GFA-Basic = http://www.tigen.org/gfabasic
Arkanoid.
PolySnd 3.0.

10

Dans le contexte décrit par Sasume, j'ai l'impression que les composantes de ton pattern composite ne porteraient pas beaucoup plus de signification que des attributs de classe. Certes ça fonctionnerait, mais je trouve dommage d'utiliser un pattern pour modéliser un problème qui finalement se représente très bien sans.
avatar
All right. Keep doing whatever it is you think you're doing.
------------------------------------------
Besoin d'aide sur le site ? Essayez par ici :)

11

Mouais, à mon avis ni Visitor ni Composite ne résolvent mon problème (ni même Strategy). Je me débrouille en synthétisant à la racine (ici « Véhicule ») les opérations que je veux pouvoir faire et ce sont elles qui seront spécialisées dans les classes filles. Banal en fait. Mais parfois quand j’ai le nez dans le guidon je ne me rends pas compte de plein de trucs. Le simple fait de venir parler du problème ici me permet de prendre moi-même du recul dessus.
avatar
« Quand le dernier arbre sera abattu, la dernière rivière empoisonnée, le dernier poisson capturé, alors vous découvrirez que l'argent ne se mange pas. »