Bonjour,
Bon, désolé pour le titre, je n'ai pas trouvé comme résumer moins vaguement ce qui m'amène !
Je cherche une bonne façon de programmer ceci :
- J'ai une collection d'objets instances d'une même classe A
- Je veux donner à l'utilisateur du programme une interface graphique (GUI) qui lui permette de modifier les attributs d'un de ces objets au choix
- Il ne doit y avoir qu'une GUI affichée en même temps
Je vois plusieurs possibilités :
Approche 1 - La classe A implémente la GUI, qu'on peut activer ou désactiver
Je n'ai pas rendu visible dans cet extrait de code le fait que la classe A a des variables membres, que la GUI permet de modifier les valeurs de certaines de ces variables, et que le résultat de foo() est fonction de ces valeurs.
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 class A { public: void setGuiActive( bool active ); void displayGui(); // Affiche le GUI seulement s'il est activé void foo(); }; vector< A > objects( 10 ); // vector pour l'exemple, mais d'autre conteneurs pourraient être utilisés objects.back().setGuiActive( true ); void mainLoop(){ for( A & a : objects ){ a.foo(); a.displayGui(); } }
Deux inconvénients avec cette approche :
- Il faut implémenter un mécanisme qui assure qu'une seule GUI est active
- Si la GUI utilise de nombreuses variables membre, la classe A est alourdie pour rien
Approche 2 - La classe A implémente la GUI, et une variable référence l'objet pour lequel on veut afficher la GUI
Ceci résout le premier inconvénient de l'approche 1, mais pas le 2eme:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13 class A { public: void displayGui(); void foo(); }; vector< A > objects( 10 ); A * selected = &objects.back(); void mainLoop(){ for( A & a : objects ) a.foo(); if( selected ) selected->displayGui(); }
- Si la GUI utilise de nombreuses variables membre, la classe A est alourdie pour rien
Approche 3 - La GUI est implémentée dans une autre classe
Ceci résout les 2 inconvénients de l'approche 1, mais en introduisant l'inconvénient que Gui référence un object A
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 class A { public: void foo(); }; class Gui { public: void setTarget( A * target); void display(); // N'affiche rien si target n'est pas définie private: A * target = nullptr; }; vector< A > objects( 10 ); Gui gui; gui.setTarget( &objects.back() ); void mainLoop(){ for( A & a : objects ) a.foo(); gui.display(); }
Cette 3e approche me semble préférable car elle ne surcharge pas la classe A, et je pars donc sur cette option. Mais peut-être aurez-vous déjà des suggestions quand à ce choix, ou une autre approche à proposer ?
Etant parti sur cette 3e approche, je cherche a bien gérer le fait que Gui référence un objet A.
Dans l'exemple que j'ai donné, c'est à l'utilisateur de Gui de faire attention à l'utilisation de pointeur invalide:
Il serait possible d'utiliser un weak_ptr pour prévenir ce problème:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5 vector< A > objects( 10 ); Gui gui; gui.setTarget( &objects.back() ); objects.clear(); gui.display(); // Aïe ! Le target de gui n'est plus valide
Je parle d'utilisateur de la classe Gui car c'est un code que je vais partager, et je voudrais donc concevoir un combo A + Gui qui soit assez générique pour d'adapter aux différents besoins des utilisateurs de ses classes, que ce soit d'autres personnes ou moi-même dans 2 ans.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14 class Gui { public: void setTarget( weak_ptr<A> target ); void display(); // N'affiche rien si target.lock() n'est plus valide private: weak_ptr<A> target; }; vector< share_ptr<A> > objects; for( int i = 0; i < 10; ++i ) objects.push_back( make_shared<A>() ); Gui gui; gui.setTarget( &objects.back() ); objects.clear(); gui.display(); // Ouf, l'utilisation et le test du weak_ptr prévient le bug
Comme cela me gène d'imposer à l'utilisateur de Gui l'usage de shared_ptr pour créer ses objects A, j'en suis venu à envisager la création d'une classe Gui qui puisse au choix utiliser un pointeur nu ou un weak_ptr. Pour faire cela j'ai posé cette question sur le forum. Et c'est parce-que koala01 y écrit que mon design lui semble douteux que j'en viens à vous demander vos avis dans ce présent sujet.
Que pensez-vous de mon choix de l'approche n°3 ?
Que pensez-vous de vouloir offrir à l'utilisateur le choix de sa stratégie de construction et destruction des objets A ?
Merci !
Partager