Laboratoire 1 - Héritage et Spécialisation
Une équipe de développement a fait l’analyse et une partie de la conception d’un programme gérant des trains. L’équipe n’avait pas encore décidé du langage final d’implémentation et a produit des artefacts de code dans un pseudo-langage.
Voici le diagramme des classes principales du programme.
- Un wagon connaît le wagon
suivant
dans le train afficher_wagon
affiche l’information complète d’un seul wagon.afficher_train
affiche l’information complète du wagon et de tous les wagons suivants du train.affréter
affrète le wagon à un marchand. Si un autre marchand a déjà affrété le wagon, celui-ci libère le wagon. Si le marchand estnull
, le wagon est libéré.monter
fait monter le voyageur dans unwagon
. Si le voyageur est déjà dans un autre wagon, il en descend automatiquementdescendre
fait descendre le voyageur de son wagon. Si le voyageur n’est pas dans un wagon, rien ne se passe.
Étape 0. Débutons
Implémentez le programme ainsi que le programme principal de test suivant (en pseudo code)
var v1 = new Voyageur("Philémon")
var v2 = new Voyageur("Peninna")
var m = new Marchand("Far★Star")
var w1 = new WagonVoyageur
v1.monter(w1)
v2.monter(w1)
var w2 = new WagonMarchandise
w1.suivant = w2
w2.affreter(m)
var w3 = new WagonMarchandise
w2.suivant = w3
w3.affreter(m)
var w4 = new WagonVoyageur
w3.suivant = w4
v2.monter(w4)
w1.afficher_train
Qui doit afficher:
VOYAGEUR: voyageur(s)=Philémon
MARCHANDISE: marchand=Far★Star
MARCHANDISE: marchand=Far★Star
VOYAGEUR: voyageur(s)=Peninna
TRAVAIL Vous devez implémenter le programme au moins 4 fois, une version pour chacun des groupes de langages suivants:
- Ruby et/ou Pharo (héritage simple dynamiquement typé)
- Python3 et/ou CLOS (héritage multiple dynamiquement typé)
- Java et/ou C# (héritage simple statiquement typé)
- C++ et/ou Nit et/ou Eiffel (héritage multiple statiquement typé)
Dans chacun des langages, vous devez vous efforcer de respecter le style et les bonnes pratiques du langage.
Assurez-vous aussi que le code soit de bonne qualité, sans redondances, lourdeurs ou fragilités.
Étape A. Multiple spécialisation
Aria, la plus jeune de l’équipe, veut ajouter une classe WagonDouble
qui transporte à la fois des voyageurs et des marchandises. Les voyageurs peuvent ainsi monter dedans, et les marchands peuvent l’affréter.
TRAVAIL Dans les langages suivants, ajoutez une nouvelle classe WagonDouble
comme sous-classe commune des classes de Wagon existantes:
- C++ et/ou Nit et/ou Eiffel
- Python3 et/ou CLOS
Assurez-vous que les méthodes afficher_wagon
soient élégantes et bien factorisées.
TRAVAIL Étendez le programme principal avec
var w5 = new WagonDouble
w4.suivant = w5
w5.affreter(m)
v2.monter(w5)
afficher_train(w1)
pour qu’il affiche en plus
DOUBLE: voyageur(s)=Peninna marchand=FarStar
TRAVAIL Pour chacun de ces langages, répertoriez aussi les modifications que vous avez dû faire dans le code existant (classes ou programme principal).
Étape B. Copions-collons
Malheureusement, l’héritage multiple n’est pas présent dans tous les langages.
Brienne, la plus robuste de l’équipe, propose de garder la classe WagonDouble
mais de la faire hériter seulement de WagonMarchandise
et de copier-coller le code de la classe WagonVoyageur
dans WagonDouble
.
TRAVAIL Faites une nouvelle version de votre programme (gardez la version de base) et appliquez la proposition pour les langages suivants.
- Java et/ou C#
- Ruby et/ou Pharo
TRAVAIL Pour chacun de ces langages, répertoriez aussi les modifications que vous avez dû faire dans le code existant (classes et programme principal).
TRAVAIL Discutez des avantages et inconvénients de la solution proposée par rapport au code des classes et par rapport à la simplicité et à la robustesse du code client (1 paragraphe).
Étape C. Agrégation
Cersei, la plus féroce de l’équipe, propose de transformer la classe WagonDouble
en classe autonome qui regroupe un attribut de type WagonVoyageur
et un de type WagonMarchandise
.
Elle écrit rapidement le code suivant au tableau pour montrer son idée.
class WagonDouble
var pour_voyageur = new WagonVoyageur
var pour_marchant = new WagonMarchandise
end
var v = new Voyageur("Philémon")
var m = new Marchand("Far★Star")
var w = new WagonDouble
v.monter(w.pour_voyageur)
w.pour_marchant.affreter(m)
TRAVAIL Faites une nouvelle version de votre programme (gardez la version de base) et appliquez la proposition pour les langages suivants.
- Java et/ou C#
- Ruby et/ou Pharo
TRAVAIL Pour chacun de ces langages, répertoriez aussi les modifications que vous avez dû faire dans le code existant (classes et programme principal).
TRAVAIL Discutez des avantages et inconvénients de la solution proposée par rapport au code des classes et par rapport à la simplicité et à la robustesse du code client (1 paragraphe).
Étape D. Fusion
Daenerys, la plus conquérante de l’équipe, propose de fusionner les 4 classes de wagons en une seule grosse classe unique Wagon
, d’ajouter deux attributs booléens is_wagon_voyageurs
et is_wagon_marchandises
, d’utiliser ces attributs pour implémenter la méthode afficher
et d’utiliser un test dynamique dans la méthode affreter
pour vérifier que is_wagon_marchandises
est vrai.
TRAVAIL Faites une nouvelle version de votre programme (gardez la version de base) et appliquez la proposition pour les langages suivants.
- Java et/ou C#
- Ruby et/ou Pharo
TRAVAIL Pour chacun de ces langages, répertoriez les modifications que vous avez dû faire dans le code existant (classes et programme principal).
TRAVAIL Discutez des avantages et inconvénients de la solution proposée par rapport au code des classes et par rapport à la simplicité et à la robustesse du code client (1 paragraphe).
Étape E. Dissociation
Ellaria, la plus retorse de l’équipe, propose de dissocier les rôles des wagons des wagons eux-mêmes.
Elle propose donc de créer deux classes, Voyage
et Fret
, qui contiennent le code spécifique des classes WagonVoyageur
et WagonMarchandise
.
Elle montre rapidement son idée au tableau.
class WagonVoyageur
super Wagon
var voyage = new Voyage
end
class WagonMarchandise
super Wagon
var fret = new Fret
end
class WagonDouble
super Wagon
var voyage = new Voyage
var fret = new Fret
end
Elle propose aussi d’utiliser un patron de conception façade pour simplifier l’utilisation des classes.
class Facade
fun affreter(m: Marchand, w: Wagon)
do
if w isa WagonMarchandise then
w.as(WagonMarchand).fret.affreter(m)
else if w isa WagonDouble then
w.as(WagonDouble).fret.affreter(m)
else
print("Pas affretable")
exit(1)
end
end
end
TRAVAIL Faites une nouvelle version de votre programme (gardez la version de base) et appliquez la proposition pour les langages suivants.
- Java et/ou C#
- Ruby et/ou Pharo
TRAVAIL Pour chacun de ces langages, répertoriez aussi les modifications que vous avez dû faire dans le code existant (classes ou programme principal).
TRAVAIL Discutez des avantages et inconvénients de la solution proposée par rapport au code des classes et par rapport à la simplicité et à la robustesse du code client (1 paragraphe).
Étape F. Finissons
Feuille est une enfant de la forêt et ne sais rien de la programmation. Elle vous laisse libre de proposer une meilleure conception des wagons doubles.
TRAVAIL Faites une dernière version de votre programme et proposez une meilleure modélisation de WagonDouble
pour les langages suivants.
- Java et/ou C#
- Ruby et/ou Pharo
TRAVAIL Discutez des avantages et inconvénients de votre proposition.
Travail à rendre
À la fin de la séance, envoyez vos programmes à l’enseignant dans une archive .zip
ou .tar.gz
contenant:
- Un répertoire par étape et un sous-répertoire par langage. Exemple
etape0/nit/
- Le code source dans le répertoire. Idéalement dans un seul fichier si le langage le permet. Exemple
etape0/nit/wagon.nit
- Les réponses aux questions doivent être indiquées dans le code source sous forme de commentaires longs.
Critères de qualité:
- Assurez-vous que le code soit petit, autonome et élégant (lisible et sans superflu)
- Autant que possible, minimisez les différences entre les langages et les versions (man
diff
) - Identifiez et justifiez et clairement les réponses aux questions