UP | HOME

Méthodes pour factoriser du code - Retour sur le TP1

Table of Contents

Session 1 - Test écrit - 18 mai 2015 - 16h30-17h45 - 0h20'

Un test écrit de vingt minutes clôturera la première session, consacrée aux interfaces et aux classe d'implémentation. Etudier la correction du TD1 et préparer le TP1.

Session 2 - Travaux dirigés - 18 mai 2015 - 16h30-17h45 - 0h55'

  • A préparer à l'avance (temps de travail : vingt minutes).

Ce TD continue le TP1. Lors de ce TP, il a été possible de réutiliser du code dans deux contextes différents :

  • d'une part, le code des opérations algébriques a pu être recopié textuellement d'une classe d'implémentation à deux autres classes d'implémentation,
  • d'autre part, deux classe d'implémentation ont pu être recopiées, afin de réutiliser leur définition de l'état, des constructeurs, des accesseurs et des fabriques.

La possibilité d'une réutilisation doit se comprendre dans le cadre de la discipline suivie, qui requiert de stratifier une classe d'implémentation en plusieurs couches avec les dépendances locales suivantes en simplifiant légèrement :

  • les accesseurs et les constructeurs dépendant des attributs,
  • les fabriques dépendant des constructeurs,
  • les services dépendant des accesseurs et des fabriques.

medias/progMod15_classeImplem-couches.svg

Couches d'une classe d'implémentation

Ainsi dans le premier cas, où seul l'état variait, seules les couches en contact devaient être modifiées. Dans le second cas, où seules les implémentations des services variaient, il était possible de conserver les couches inférieures, des attributs aux accesseurs et fabriques.

Cependant, la recopie textuelle (le "copier-coller") n'est pas une bonne pratique en programmation. Imaginons qu'on veuille faire évoluer le code copié, pour l'améliorer ou le corriger : dans ce cas, toutes les copies doivent être mises à jour, ce qui suppose qu'on en conserve un référencement exhaustif. Plutôt que de recopier, on préfère factoriser : le facteur commun est alors partagé. Dans ce TD, nous allons étudier deux méthodes de factorisation, fondées sur l'héritage.

Possibles factorisations dans le TP1

A partir du schéma des types utilisés dans le TP1, déterminer toutes les factorisations possibles.

Approche descendante ("top-down")

Compléter le code de manière à réaliser le schéma suivant.

medias/progMod15_td2_topDown.png

Approche descendante - Factorisation des services

interface Nat 
  extends MonoideAdditif<Nat>, MonoideMultiplicatif<Nat>, FabriqueNat<Nat>{
  ... // Accesseurs
}

// TODO - à compléter
................ class AlgebreNatParInt ................................ {
  // Services algébriques
        @Override
        public Nat zero() {
          ..............................................................
        }
        @Override
        public Nat somme(Nat x) {
          ..............................................................
        }
        @Override
        public Nat un() {
          ..............................................................
        }
        @Override
        public Nat produit(Nat x) {
          ..............................................................
        }
        @Override
        public String toString() {
          ..............................................................
        }
        @Override
        public boolean equals(Object obj) {
          ..............................................................
          ..............................................................
          ..............................................................
          ..............................................................
        }
}
class NatParInt ....................................................... {
  ... // Etat, constructeurs, accesseurs, fabriques
}
class Succ ............................................................ {
  ... // Etat, constructeurs, accesseurs, fabriques
}
class Zero ............................................................ {
  ... // Etat, constructeurs, accesseurs, fabriques
}

Approche ascendante ("bottom-up")

Compléter le code de manière à réaliser le schéma suivant.

medias/progMod15_td2_bottomup.png

Approche ascendante - Factorisation de l'état, des accesseurs et des fabriques

interface Nat 
  extends MonoideAdditif<Nat>, MonoideMultiplicatif<Nat>, FabriqueNat<Nat>{
  ... // Accesseurs
}

// TODO - à compléter
................ class Zero ........................................... {
        @Override
        public Nat creer(int val) {
          ..............................................................
          ..............................................................
          ..............................................................
        }
        @Override
        public int val() {
          ..............................................................
        }
        @Override
        public boolean estNul() {
          ..............................................................
        }
        @Override
        public Nat predecesseur() {
          ..............................................................
        }
        @Override
        public String toString() {
          ..............................................................
        }
        @Override
        public boolean equals(Object obj) {
          ..............................................................
          ..............................................................
          ..............................................................
          ..............................................................
        }
}
................ class Succ ........................................... {

        private Nat predecesseur;

        public Succ(Nat predecesseur) {
          ..............................................................        
        }

        @Override
        public Nat creer(int val) {
          ..............................................................
          ..............................................................
          ..............................................................
        }
        @Override
        public int val() {
          ..............................................................        
        }
        @Override
        public boolean estNul() {
          ..............................................................
        }

        @Override
        public Nat predecesseur() {
          ..............................................................
        }
        @Override
        public String toString() {
          ..............................................................
        }
        @Override
        public boolean equals(Object obj) {
          ..............................................................
          ..............................................................
          ..............................................................
          ..............................................................
          ..............................................................
          ..............................................................
        }
}
class ZeroRec ........................................................ {
        @Override
        public Nat zero() {
          ..............................................................
        }
        @Override
        public Nat somme(Nat x) {
          ..............................................................
        }
        @Override
        public Nat un() {
          ..............................................................
        }
        @Override
        public Nat produit(Nat x) {
          ..............................................................
        }

        @Override
        public Nat creer() {
          ..............................................................
        }
        @Override
        public Nat creer(Nat predecesseur) {
          ..............................................................
        }
}
class SuccRec ........................................................ {
        public SuccRec(Nat predecesseur) {
          ..............................................................
        }
        @Override
        public Nat zero() {
          ..............................................................
        }

        @Override
        public Nat somme(Nat x) {
          ..............................................................
        }
        @Override
        public Nat un() {
          ..............................................................
        }
        @Override
        public Nat produit(Nat x) {
          ..............................................................
        }
        @Override
        public Nat creer() {
          ..............................................................
        }
        @Override
        public Nat creer(Nat predecesseur) {
          ..............................................................
        }
}

Vers l'héritage multiple

L'approche descendante permet de factoriser les services de la couche supérieure. L'approche ascendante permet de factoriser les couches basses, de l'état aux accesseurs, aux fabriques et aux services universels (toString, equals). L'idéal serait de pouvoir combiner ces deux factorisations. Cependant, en Java, ce n'est pas possible sous la forme que nous avons utilisée : il est impossible d'hériter de deux classes, celle implémentant les couches basses et celle implémentant les services de la couche supérieure. Cependant, à partir de la version 8 de Java, il est possible de définir dans les interfaces des implémentations de méthodes, dites alors par défaut. Ainsi, on peut définir une interface implémentant les services de la couche supérieure.

Compléter le code de manière à réaliser le schéma suivant.

medias/progMod15_td2_heritageMultiple.png

Héritage multiple - Double factorisation

interface Nat 
  extends MonoideAdditif<Nat>, MonoideMultiplicatif<Nat>, FabriqueNat<Nat>{
  ... // Accesseurs
}

// TODO - à compléter
interface NatCalculantInt extends Nat {
  // Implémentations par défaut
        @Override
        default         
        public Nat zero() {
          ..............................................................
        }
        @Override
        default
        public Nat somme(Nat x) {
          ..............................................................
        }
        @Override
        default
        public Nat un() {
          ..............................................................
        }
        @Override
        default
        public Nat produit(Nat x) {
          ..............................................................
        }
}
................ class IntPositif ........................................... {
        private int val;
        public IntPositif(int val) {
          ..............................................................
        }
        @Override
        public Nat creer() {
          ..............................................................
        }
        @Override
        public Nat creer(Nat  predecesseur) {
          ..............................................................
        }
        @Override
        public int val() {
          ..............................................................
        }
        @Override
        public boolean estNul() {
          ..............................................................
        }
        @Override
        public Nat predecesseur() {
          ..............................................................
          ..............................................................
          ..............................................................
        }
        @Override
        public String toString() {
          ..............................................................
                return Integer.toString(this.val());
        }
        @Override
        public boolean equals(Object obj) {
          ..............................................................
          ..............................................................
          ..............................................................
          ..............................................................
        }
}
class NatParInt .......................................................  {
        public NatParInt(int val) {
          ..............................................................                
        }
        @Override
        public Nat creer(int val) {
          ..............................................................
        }
}

Last Updated 2015-05-26T15:00+0200. Comments or questions: Send a mail.