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 est null, le wagon est libéré.
  • monter fait monter le voyageur dans un wagon. Si le voyageur est déjà dans un autre wagon, il en descend automatiquement
  • descendre 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