Quelques raccourcis :
Ce petit travail pratique a été pensé pour vous faire réfléchir, et pour vous divertir. De par sa structure, il fait en sorte qu'on puisse "tricher" en résolvant les versions les plus simples du problème, mais qu'il faille faire un effort de conception pour résoudre le problème dans son acception générale – surtout si vous souhaitez le petit bonus.
Si vous avez un design propre et élégant, vous aurez du plaisir. Si vous trichez, ce sera... une expérience de vie. 🙂
Vous devez développer un ensemble de classes permettant de construire des boîtes et de les imbriquer. Nous avons abordé en classe une solution à ce problème, développée de manière incrémentale de manière à aborder le problème de la refactorisation du code, mais cette fois, c'est à un problème de design que vous êtes conviés.
C'est un problème a priori facile à résoudre. Dans une acception C++, l'idée est que si le programme suivant :
#include <iostream>
int main() {
cout << "J'aime mon prof" << endl;
}
... devrait afficher cela :
J'aime mon prof
... alors le programme suivant :
#include "Boite.h"
#include <iostream>
int main() {
cout << Boite{ "J'aime mon prof" } << endl;
}
... devrait afficher cela :
+---------------+
|J'aime mon prof|
+---------------+
...et que si le programme suivant :
#include <iostream>
int main() {
cout << "J'aime\nmon \"prof\"" << endl;
cout << R"(Moi
"aussi")" << endl;
}
... devrait afficher cela :
J'aime
mon "prof"
Moi
"aussi"
... alors le programme suivant :
#include "Boite.h"
#include <iostream>
int main() {
cout << Boite{ "J'aime\nmon \"prof\"" } << endl;
cout << Boite { R"(Moi
"aussi")" } << endl;
}
... devrait afficher cela :
+----------+
|J'aime |
|mon "prof"|
+----------+
+-------+
|Moi |
|"aussi"|
+-------+
Facile non?
Évidemment, ça devient plus intéressant si on inclut les combos verticaux et horizontaux. Par exemple, ceci :
#include "Boite.h"
#include <iostream>
int main() {
cout << Boite{ ComboVertical{ Boite { "J'aime" }, Boite { "mon \"prof\"" } } << endl;
cout << Boite { ComboHorizontal{ Boite { "Moi" }, Boite { "\"aussi\"" } } << endl;
}
... doit afficher cela :
+----------+
|J'aime |
|----------|
|mon "prof"|
+----------+
+-----------+
|Moi|"aussi"|
+-----------+
À titre d'exemple, le programme de test C++ suivant :
#include "boite.h"
#include "combovertical.h"
#include "combohorizontal.h"
#include <string_view>
#include <iostream>
int main() {
using namespace std;
Boite b;
cout << b << endl;
constexpr auto texte = R"(Man! Hey!!!
ceci est un test
multiligne)"sv;
constexpr auto aut_texte = R"(Ceci
itou, genre)"sv;
Boite b0{ texte };
Boite b1{ aut_texte };
cout << b0 << endl << b1 << endl;
ComboVertical cv{ b0, b1 };
cout << Boite{ cv } << endl;
ComboHorizontal ch{ b0, b1 };
cout << Boite{ ch } << endl;
ComboVertical cvplus{ Boite{ cv }, Boite{ ch } };
cout << Boite{ cvplus } << endl;
ComboHorizontal chplus{ Boite{ cv }, Boite{ ch } };
cout << Boite{ chplus } << endl;
ComboVertical cvv{ Boite{ chplus }, Boite{ "coucou" } };
cout << Boite{ cvv } << endl;
cout << Boite{
ComboHorizontal{
Boite{ "a\nb\nc\nd\ne" },
Boite{
ComboVertical{
Boite{ "allo" }, Boite{ "yo"sv }
}
}
}
} << endl;
cout << Boite{
ComboHorizontal{ Boite{ "Yo"sv }, {} }
} << endl;
cout << Boite{
ComboHorizontal{ {}, Boite{ "Ya" } }
} << endl;
cout << Boite{ ComboHorizontal{ {}, {} } } << endl;
cout << Boite{
ComboVertical{ Boite{ "Yip" }, {} }
} << endl;
cout << Boite{
ComboVertical{ {}, Boite{ "Yap"sv } }
} << endl;
cout << Boite{ ComboVertical{ {}, {} } } << endl;
}
...doit résulter en l'affichage suivant :
++
++
+----------------+
|Man! Hey!!! |
|ceci est un test|
|multiligne |
+----------------+
+-----------+
|Ceci |
|itou, genre|
+-----------+
+----------------+
|Man! Hey!!! |
|ceci est un test|
|multiligne |
|----------------|
|Ceci |
|itou, genre |
+----------------+
+----------------------------+
|Man! Hey!!! |Ceci |
|ceci est un test|itou, genre|
|multiligne | |
+----------------------------+
+----------------------------+
|Man! Hey!!! |
|ceci est un test |
|multiligne |
|----------------------------|
|Ceci |
|itou, genre |
|----------------------------|
|Man! Hey!!! |Ceci |
|ceci est un test|itou, genre|
|multiligne | |
+----------------------------+
+---------------------------------------------+
|Man! Hey!!! |Man! Hey!!! |Ceci |
|ceci est un test|ceci est un test|itou, genre|
|multiligne |multiligne | |
|----------------| | |
|Ceci | | |
|itou, genre | | |
+---------------------------------------------+
+---------------------------------------------+
|Man! Hey!!! |Man! Hey!!! |Ceci |
|ceci est un test|ceci est un test|itou, genre|
|multiligne |multiligne | |
|----------------| | |
|Ceci | | |
|itou, genre | | |
|---------------------------------------------|
|coucou |
+---------------------------------------------+
+------+
|a|allo|
|b|----|
|c|yo |
|d| |
|e| |
+------+
+---+
|Yo||
+---+
+---+
||Ya|
+---+
+-+
+-+
+---+
|Yip|
|---|
+---+
+---+
|---|
|Yap|
+---+
++
||
++
Plus en détail :
Il s'agit d'un problème un peu plus costaud qu'il n'y paraît, ce qui explique que je vous laisse du temps pour le faire. Profitez de ce temps, et cherchez à obtenir un design qui vous semble de qualité : concis, modifiable, esthétique, clair. Si votre design est complexe, ou si vous codez sans réfléchir, ceci peut être casse-gueule. Si vous y allez avec délicatesse, votre solution pourrait être fort élégante.
Notez que nous avons vu plusieurs techniques cette session qui sont susceptibles de vous être utiles pour résoudre ce problème. Profitez-en pour expérimenter!
Si vous abordez ce problème en C++, faites attention à la gestion de la mémoire. Je vous invite à privilégier des unique_ptr lorsque cela s'avère possible, car ils allègeront l'écriture de votre solution et règleront la plupart de vos problèmes (si des problèmes apparaissent en utilisant des unique_ptr, en fait, c'est que votre code aurait probablement fui sans eux!),
Pour un équivalent C#, si cela vous intéresse, le code client serait :
using System;
using System.Collections.Generic;
namespace BoitesCdiese
{
class Program
{
static void Main(string[] args)
{
Boite b = new Boite();
Boite.Afficher(b);
Boite.Afficher(new Boite("yo"));
string texte = @"Man! Hey!!!
ceci est un test
multiligne";
string aut_texte = "Ceci\nitou, genre";
Boite b0 = new Boite(texte);
Boite b1 = new Boite(aut_texte);
Boite.Afficher(b0);
Boite.Afficher(b1);
ComboVertical cv = new ComboVertical(b0, b1);
Boite.Afficher(new Boite(cv));
ComboHorizontal ch = new ComboHorizontal(b0, b1);
Boite.Afficher(new Boite(ch));
ComboVertical cvplus = new ComboVertical( new Boite(cv), new Boite(ch));
Boite.Afficher(new Boite(cvplus));
ComboHorizontal chplus = new ComboHorizontal(new Boite(cv), new Boite(ch));
Boite.Afficher(new Boite(chplus));
ComboVertical cvv = new ComboVertical(new Boite(chplus), new Boite("coucou"));
Boite.Afficher(new Boite(cvv));
Boite.Afficher(new Boite(
new ComboHorizontal(
new Boite("a\nb\nc\nd\ne"),
new Boite(
new ComboVertical(
new Boite("allo"), new Boite("yo")
)
)
)
)
);
Boite.Afficher(
new Boite(new ComboHorizontal(new Boite("Yo"), new Boite()))
);
Boite.Afficher(
new Boite(new ComboHorizontal(new Boite(), new Boite("Ya")))
);
Boite.Afficher(
new Boite(new ComboHorizontal(new Boite(), new Boite()))
);
Boite.Afficher(
new Boite(new ComboVertical(new Boite(), new Boite()))
);
Boite.Afficher(
new Boite(new ComboVertical(new Boite("Yip"), new Boite()))
);
Boite.Afficher(
new Boite(new ComboVertical(new Boite(), new Boite("Yap")))
);
}
}
}
... ce qui n'est pas nécessairement plus simple, mais c'est une question de point de vue je présume. L'affichage attendu est le même qu'en C++.
De même, pour un équivalent Java, on aurait :
public class Program {
public static void main(String[] args) {
Boite b = new Boite();
Boite.afficher(b);
Boite.afficher(new Boite("yo"));
String texte = "Man! Hey!!!\nceci est un test\nmultiligne";
String aut_texte = "Ceci\nitou, genre";
Boite b0 = new Boite(texte);
Boite b1 = new Boite(aut_texte);
Boite.afficher(b0);
Boite.afficher(b1);
ComboVertical cv = new ComboVertical(b0, b1);
Boite.afficher(new Boite(cv));
ComboHorizontal ch = new ComboHorizontal(b0, b1);
Boite.afficher(new Boite(ch));
ComboVertical cvplus = new ComboVertical( new Boite(cv), new Boite(ch));
Boite.afficher(new Boite(cvplus));
ComboHorizontal chplus = new ComboHorizontal(new Boite(cv), new Boite(ch));
Boite.afficher(new Boite(chplus));
ComboVertical cvv = new ComboVertical(new Boite(chplus), new Boite("coucou"));
Boite.afficher(new Boite(cvv));
Boite.afficher(new Boite(
new ComboHorizontal(
new Boite("a\nb\nc\nd\ne"),
new Boite(
new ComboVertical(
new Boite("allo"), new Boite("yo")
)
)
)
)
);
Boite.afficher(
new Boite(new ComboHorizontal(new Boite("Yo"), new Boite()))
);
Boite.afficher(
new Boite(new ComboHorizontal(new Boite(), new Boite("Ya")))
);
Boite.afficher(
new Boite(new ComboHorizontal(new Boite(), new Boite()))
);
Boite.afficher(
new Boite(new ComboVertical(new Boite(), new Boite()))
);
Boite.afficher(
new Boite(new ComboVertical(new Boite("Yip"), new Boite()))
);
Boite.afficher(
new Boite(new ComboVertical(new Boite(), new Boite("Yap")))
);
}
}
... ce qui est aussi laborieux, mais voilà. L'affichage attendu est le même qu'en C++.
Si vous abordez ce problème en Java ou en C#, faites attention au partage des ressources. Je vous invite à prendre soin de dupliquer les objets que vous manipulez pour éviter qu'une redimension fortuite n'endommage un objet manipulé indirectement.
Votre chic prof, quand il a résolu le problème, a refactorisé de manière relativement importante la solution existante jusque là. Vous n'avez absolument pas à faire comme lui. Pris d'un point de vue aérien, le schéma de sa solution est :
![]() |
Quelques remarques :
Pris d'un peu plus près, nous avons :
![]() |
Quelques remarques :
À titre d'exemple, pour mes fins, la classe ComboVertical::Enumerateur dérive d'IEnumerateur<IBoite::str_type> et fait en sorte que j'itère d'abord sur la section du haut, puis (brièvement) sur la « section » du centre, puis sur la section du bas, ce qui cache à la Boite englobante les détails d'implémentation de ce qu'elle « contient ».
Étant donné que ce travail pratique a été proposé par le passé et a acquis, semble-t-il, une certaine... réputation, j'ai pris sur moi de propose une option vous permettant d'aller chercher un petit bonus si tel est votre souhait.
Ce bonus prend la forme d'un MonoCombo, représentant une boîte encadrée dans une Boite. Évidemment, un MonoCombo peut être placé dans n'importe quelle Boite, et peut contenir n'importe quelle Boite.
Un exemple de programme C++ utilisant aussi des MonoCombo suit. Vous pouvez extrapoler à partir des exemples Java et C# plus haut pour en arriver au même résultat :
#include "boite.h"
#include "combovertical.h"
#include "combohorizontal.h"
#include "monocombo.h"
#include <string_view>
#include <iostream>
int main() {
using namespace std;
Boite b;
cout << b << endl;
constexpr auto texte = R"(Man! Hey!!!
ceci est un test
multiligne)"sv;
constexpr auto aut_texte = R"(Ceci
itou, genre)"sv;
Boite b0{ texte };
Boite b1{ aut_texte };
cout << b0 << endl << b1 << endl;
ComboVertical cv{ b0, b1 };
cout << Boite{ cv } << endl;
ComboHorizontal ch{ b0, b1 };
cout << Boite{ ch } << endl;
ComboVertical cvplus{ Boite{ cv }, Boite{ ch } };
cout << Boite{ cvplus } << endl;
ComboHorizontal chplus{ Boite{ cv }, Boite{ ch } };
cout << Boite{ chplus } << endl;
ComboVertical cvv{ Boite{ chplus }, Boite{ "coucou" } };
cout << Boite{ cvv } << endl;
cout << Boite{
ComboHorizontal{
Boite{ "a\nb\nc\nd\ne" },
Boite{
ComboVertical{
Boite{ "allo" }, Boite{ "yo"sv }
}
}
}
} << endl;
cout << Boite{
ComboHorizontal{ Boite{ "Yo"sv }, {} }
} << endl;
cout << Boite{
ComboHorizontal{ {}, Boite{ "Ya" } }
} << endl;
cout << Boite{
ComboHorizontal{ {}, {} }
} << endl;
cout << Boite{
ComboVertical{ Boite{ "Yip" }, {} }
} << endl;
cout << Boite{
ComboVertical{ {}, Boite{ "Yap"sv } }
} << endl;
cout << Boite{
ComboVertical{ {}, {} }
} << endl;
cout << Boite{ MonoCombo { Boite { "allo" } } } << endl;
cout << Boite{ MonoCombo{ Boite{ MonoCombo { Boite { "allo" } } }} } << endl;
cout << Boite{
ComboVertical{
Boite { MonoCombo{ Boite{ MonoCombo { Boite { "allo" } } }} },
Boite{ "Eh ben" }
}
} << endl;
cout << Boite{
ComboHorizontal{
Boite { MonoCombo{ Boite{ MonoCombo { Boite { "allo" } } }} },
Boite{ ComboVertical {
Boite { "Eh ben" },
Boite { MonoCombo{ Boite {
ComboHorizontal{ Boite { "yo" }, Boite { "hey" } }
} } }
} }
}
} << endl;
}
L'affichage attendu serait alors :
++
++
+----------------+
|Man! Hey!!! |
|ceci est un test|
|multiligne |
+----------------+
+-----------+
|Ceci |
|itou, genre|
+-----------+
+----------------+
|Man! Hey!!! |
|ceci est un test|
|multiligne |
|----------------|
|Ceci |
|itou, genre |
+----------------+
+----------------------------+
|Man! Hey!!! |Ceci |
|ceci est un test|itou, genre|
|multiligne | |
+----------------------------+
+----------------------------+
|Man! Hey!!! |
|ceci est un test |
|multiligne |
|----------------------------|
|Ceci |
|itou, genre |
|----------------------------|
|Man! Hey!!! |Ceci |
|ceci est un test|itou, genre|
|multiligne | |
+----------------------------+
+---------------------------------------------+
|Man! Hey!!! |Man! Hey!!! |Ceci |
|ceci est un test|ceci est un test|itou, genre|
|multiligne |multiligne | |
|----------------| | |
|Ceci | | |
|itou, genre | | |
+---------------------------------------------+
+---------------------------------------------+
|Man! Hey!!! |Man! Hey!!! |Ceci |
|ceci est un test|ceci est un test|itou, genre|
|multiligne |multiligne | |
|----------------| | |
|Ceci | | |
|itou, genre | | |
|---------------------------------------------|
|coucou |
+---------------------------------------------+
+------+
|a|allo|
|b|----|
|c|yo |
|d| |
|e| |
+------+
+---+
|Yo||
+---+
+---+
||Ya|
+---+
+-+
+-+
+---+
|Yip|
|---|
+---+
+---+
|---|
|Yap|
+---+
++
||
++
+------+
|+----+|
||allo||
|+----+|
+------+
+--------+
|+------+|
||+----+||
|||allo|||
||+----+||
|+------+|
+--------+
+--------+
|+------+|
||+----+||
|||allo|||
||+----+||
|+------+|
|--------|
|Eh ben |
+--------+
+-----------------+
|+------+|Eh ben |
||+----+||--------|
|||allo|||+------+|
||+----+|||yo|hey||
|+------+|+------+|
+-----------------+
Vous constaterez que les avertissements d'usage s'appliquent encore ici : si votre design est propre, ce sera un ajout relativement simple. Si vous essayez d'y aller par force brute et de tricher, ce sera... douloureux.
Prenez le temps de réfléchir à votre design. C'est un travail pratique amusant, et instructif.