Laboratoire de raffinement

Ce laboratoire est fait en deux parties, la première en Nit, pour jouer avec le raffinement de classes, et la seconde en Java pour essayer de reproduire dans un langage à objets habituel.

Le thème est de faire un petit convertisseur Logo vers SVG en séparant les préoccupations.

Afin de ne pas tout écrire, on vous donne à disposition un code incomplet qu'il faudra étendre.

Étape 1: Programmation graphique

Le langage Logo permet de faire de la programmation graphique amusante. Dans ce laboratoire, on considère des programmes Logos très simples composé seulement des 3 instructions forward, turn right et repeat. La structure d'un programme Logo est donnée dans le fichier logo.nit.

Pour simplifier la création d'un objet programme logo, on fournit une API fluide via la classe LogoWriter et la fonction logo.

  • Lisez et comprenez le module logo.nit
  • Implémentez la méthode to_s de LogoProg et LogoRepeat
  • Vérifiez que votre programme fonctionne en exécutant le module logo
$ nit logo.nit
REPEAT 5 [FD 50 RT 144]
REPEAT 4 [FD 50 RT 90] FD 50 RT -135 FD 35 RT -90 FD 35 RT 225

Aide 1: for item in coll do ... pour itérer sur une collection

Aide 2: for i in [0..len[ do ... pour itérer len fois.

Aide 3: "A {b} C {d}" est équivalent à "A " + b.to_s + " C " + d.to_s.

Aide 4: [a,b,c].join("x") est équivalent à "{a}x{b}x{c}".

Étape 2: La tortue entre lentement en scène

Nous avons des programmes Logo, mais nous pouvons rien en faire pour l'instant.

Il suffit d'ajouter une tortue et d'implémenter les services qui déplacent la tortue. Comme en Nit il est possible de raffiner des classes existantes, il suffit d'implémenter les services qui vont bien, directement dans les raffinements des classes.

Dans le module turtle.nit, on vous fournit une classe Turtle et on raffine la classe Logo.

  • Lisez et comprenez le module turtle.nit
  • Implémentez les méthodes apply des sous-classes de Logo
  • Vérifiez que votre programme fonctionne en exécutant le module turtle
$ nit turtle.nit
(50.0,0.0;0.0)
(10.0,20.0;90.0)
(55.0,55.0;180.0)

Étape 3: Une visite inattendue

Le patron de conception Visiteur permet de séparer un algorithme d'une structure de données.

Il est intéressant dans les langages à objets classiques car il permet de définir de nouveaux traitements sur une structure de données existante complexe que l'on ne veut/peut pas modifier.

Dans ce laboratoire, la structure de données considérée est la classe Logo et ses sous-classes. Elle est complexe car elle est hétérogène (plusieurs catégories d'instructions) et récursive (à cause de l'instruction repeat).

Comme en Nit il est possible de raffiner les classes existantes dans un module différent, le visiteur est moins utile. La preuve: c'est exactement ce que l'on a fait à l'étape précédente où on a ajouté le comportement apply aux classes existantes.

Toutefois, le visiteur a un autre avantage, il permet de factoriser le code de parcours de la structure de données. En effet, si on regarde les classes LogoProg et LogoRepeat on se rend compte que le comportement sera très semblable d'un algorithme à l'autre: il suffit pour s'en convaincre de regarder le code de apply.

Également, lorsque qu'un algorithme doit visiter les éléments, il faut généralement maintenir un état spécifique à l'algorithme. En programmation à objets, il est raisonnable de maintenir cet état dans un objet spécifique qui est passé en paramètre dans les méthodes des éléments. Cet objet est un bon candidat pour devenir un visiteur.

Le module visitor.nit introduit la structure abstraire d'un visiteur. Notez que grâce au raffinement on peut introduire l'instrumentation du visiteur dans un sous-module sans toucher aux classes originales. Notez aussi que visitor.nit ne dépend pas de turtle.nit.

Dans cette étape nous allons implémenter le calcul d'une boite englobante un programme Logo. Pour ce faire il faut visiter les instructions d'un programme en mettant à jour la position de la tortue et en grossissant la boite englobante. Une bonne conception indiquerait de créer un visiteur qui agrège ces deux informations.

  • Lisez et comprenez les modules visitor.nit et bound.nit.
  • Finissez l'implémentation de ces deux modules. En particulier de la classe BoundVisitor.
  • Vérifiez que votre programme fonctionne en exécutant le module bound
$ nit bound.nit
(0.0,0.0)--(10.0,0.0)
(0.0,-18.164)--(50.0,29.389)
(0.0,-24.749)--(50.0,50.0)

Aide 1: Dans visitor.nit, inspirez-vous de apply pour implémenter visit_all.

Aide 2: Dans bound.nit, vous pouvez raffiner la classe Logo et ses sous-classes pour ajouter du service.

Étape 4: Dessinons

Maintenant que nous maîtrisons les visiteurs, il ne reste qu'à générer le SVG.

Le module canvas.nit indépendant fournit un moyen simpliste de générer du SVG.

  • Lisez et comprenez les modules canvas.nit et trace.nit.
  • Finissez d'implémenter trace.nit.
  • Vérifiez que votre programme fonctionne en exécutant le module trace
$ nit trace.nit

Aide: initialisez la tortue en (250.0,100.0) pour quelle soit au milieu du canevas SVG.

Étape 5: Un coup en haut, un coup en bas

On imagine que les modules précédents sont fournis par un tiers, on ne peut pas les modifier. Toutefois on veut pouvoir les faire évoluer pour les adapter à de nouveaux besoins.

On va donc créer un nouveau module pen.nit qui va importer tous les modules précédents (en fait seul trace suffit) et spécialiser ou raffiner les classes existantes.

L'objectif est de créer deux nouvelles instructions «pen up» (PU) et «pen down» (PD) qui permettent de lever ou poser le crayon afin de pouvoir déplacer la tortue sans tracer sur le canevas lorsque le crayon est levé.

  • Implémentez tout ce qu'il faut dans pen.nit
  • Vérifiez que votre programme fonctionne en exécutant le module pen
$ nit pen.nit
PU FD -200 PD REPEAT 7 [REPEAT 4 [FD 50 RT 90] FD 50 RT -135 FD 35 RT -90 FD 35 RT 225 PU FD 60 PD]

Indice: pour commencer, raffinez la classe Turtle pour rajouter un état indiquant si le crayon est levé ou posé.

Étape 6: Vous prendrez-bien un peu de café?

Réimplémentez ce programme en Java (ou en C#) en essayant de séparer au mieux les préoccupations.

  • Créer une hiérarchie de classes Logo (sans tortue) mais instrumentée avec une classe abstraire Visitor.
  • Créez un visiteur particulier qui génère du SVG.
  • De façon indépendante (sans modifier les classes Logo existantes, ni le visiteur abstrait) introduisez les deux nouvelles instructions pen up et pen down.
  • Quels sont les irritants de langages comme Java ou C# en terme de modularité et d'évolution de code ?