UP | HOME

Méthodes pour factoriser du code - Héritage et agrégation avec délégation

Table of Contents

Session 2 - Test écrit - 8 juin 2015 - 16h30-17h45 - 0h20'

Un test écrit de vingt minutes clôturera la seconde session, consacrée à la factorisation en utilisant l'héritage. En préparation, étudier la correction du TD2 et celle du TP2.

Session 3 - Travaux dirigés - 8 juin 2015 - 16h30-17h45 - 0h55'

Les exercices qui suivent concernent une architecture en couches et passent en revue différentes méthodes de factorisation du code pour de telles architectures :

  • héritage avec approche ascendante,
  • héritage avec approche descendante,
  • héritage multiple (en Java 8 uniquement),
  • agrégation avec délégation.

Parmi ces quatre méthodes, celles recourant à l'héritage ne sont pas nouvelles : elles ont été étudiées pendant la seconde session. La seule nouvelle n'utilise pas l'héritage, mais l'agrégation avec délégation.

On cherche à programmer un agent cherchant à envoyer un message (sur un réseau) en utilisant un canal de communication, chargé de l'émission du message sur le réseau. Ce processus possède deux degrés de liberté, ou deux points de variation :

  • la décomposition du message à envoyer en plusieurs fragments à émettre,
  • le protocole de communication utilisé par le canal.

On suppose par la suite que deux techniques de décomposition sont utilisées :

  • décomposition d'un message de taille quelconque en des fragments de taille limitée,
  • pas de décomposition, le message étant simplement encapsulé pour le transport sur le réseau.

De même, on suppose que deux protocoles peuvent être utilisés, qu'on appellera "Protocole 1" et "Protocole 2" simplement. De ces deux hypothèses, il résulte qu'il est possible d'obtenir quatre combinaisons.

DécoupageEncapsulation
Protocole 1XX
Protocole 2XX

Quatre combinaisons d'implémentations

Dans la suite, on modélise la communication sur le réseau par une sortie sur la console, préfixée par le nom du protocole.

public void emettre(String msg) {
        System.out.println("protocole X : " + msg);
}

On implémente ainsi l'encapsulation et le découpage des messages.

// Encapsulation
public void envoyer(String msg) {
        this.emettre(msg);
}
// Découpage
public void envoyer(String msg) {
        int TAILLE = 5;
        StringBuilder m = new StringBuilder(msg);
        int q = msg.length() / TAILLE;
        int r = msg.length() % TAILLE;
        for(int j = 0; j < q; j++){
                this.emettre(m.substring(j * TAILLE, (j+1) * TAILLE));
        }
        this.emettre(m.substring(q * TAILLE, q * TAILLE + r));
}

Dans la suite on abrégera le code de la première méthode en ENC et celui de la seconde en DEC. Enfin, pour chaque classe implémentée, on indique dans son nom les choix réalisés :

  • DecoupantMessages et EncapsulantMessages pour le découpage et l'encapsulation respectivement,
  • Protocole1 et Protocole2 pour les protocoles 1 et 2 respectivement.

Pour illustrer ce type d'architecture, prenons à titre d'exemple Internet. Les messages y sont décomposés en paquets dont la taille maximale est fixée par le MTU (Maximum Transmission Unit). Deux protocoles peuvent servir au transport des messages : UDP (User Datagram Protocol en mode non connecté, comme le courrier postal, utilisé pour le streaming par exemple) et TCP (Transmission Control Protocol en mode connecté, comme le téléphone, utilisé pour les pages Web).

Hiérarchie d'interfaces

Définir dans le paquet td3

  • une interface Agent déclarant la méthode void envoyer(String msg),
  • une interface Canal déclarant la méthode void emettre(String msg),
  • une interface AgentCommuniquant héritant des deux interfaces précédentes.

medias/progMod15_td3_interfaces.png

Hiérarchie d'interfaces - Un agent communiquant

interface Agent {
  ......................................................................
}
interface Canal {
  ......................................................................
}
interface AgentCommuniquant ............................................
  ......................................................................

Héritage - Approche ascendante

On réalise les quatre combinaisons en factorisant la couche basse, suivant une approche ascendante pour l'héritage.

Réaliser le schéma suivant dans le paquet td3.ascendant.

medias/progMod15_td3_ascendant.png

Approche ascendante - Factorisation de la couche basse

class CanalOutProtocole1 ...............................................
{
  ......................................................................
  ......................................................................
  ......................................................................
  ......................................................................
}
class CanalOutProtocole2 ...............................................
{
  ......................................................................
  ......................................................................
  ......................................................................
  ......................................................................
}
class AgentDecoupantMessagesPourProtocole1 .............................
  ......................................................................
{
        @Override
        public void envoyer(String msg) {
          ..............................................................
          ...
        }
}
class AgentEncapsulantMessagesPourProtocole1 ...........................
  ......................................................................
{
        @Override
        public void envoyer(String msg) {
          ..............................................................
          ...
        }
}
class AgentDecoupantMessagesPourProtocole2 .............................
  ......................................................................
{
        @Override
        public void envoyer(String msg) {
          ..............................................................
          ...
        }
}
class AgentEncapsulantMessagesPourProtocole2 ...........................
  ......................................................................
{
        @Override
        public void envoyer(String msg) {
          ..............................................................
        }
}

Héritage - Approche descendante

On réalise les quatre combinaisons en factorisant la couche haute, suivant une approche descendante pour l'héritage.

Réaliser le schéma suivant dans le paquet td3.descendant.

medias/progMod15_td3_descendant.png

Approche descendante - Factorisation de la couche haute

........................................................................
  class AgentDecoupantMessages .........................................
{
        @Override
        public void envoyer(String msg) {
          ..............................................................
        }
}
........................................................................
  class AgentEncapsulantMessages .......................................
{
        @Override
        public void envoyer(String msg) {
          ..............................................................
        }
}
class AgentDecoupantMessagesPourProtocole1 .............................
  ......................................................................
{
        @Override
        public void emettre(String msg) {
          ..............................................................
        }
}
class AgentDecoupantMessagesPourProtocole2 .............................
  ......................................................................
{
        @Override
        public void emettre(String msg) {
          ..............................................................
        }
}
class AgentEncapsulantMessagesPourProtocole1 ...........................
  ......................................................................
{
        @Override
        public void emettre(String msg) {
          ..............................................................
        }
}
class AgentEncapsulantMessagesPourProtocole2 ...........................
  ......................................................................
{
        @Override
        public void emettre(String msg) {
          ..............................................................
        }
}

Héritage multiple (Java 8 seulement)

On réalise les quatre combinaisons en factorisant la couche haute et celle basse.

Réaliser le schéma suivant dans le paquet td3.heritageMultiple.

medias/progMod15_td3_multiple.png

Héritage multiple - Factorisation des deux couches

interface AgentDecoupantMessages .......................................
  ......................................................................
{
        @Override
        default
        public void envoyer(String msg) {
          ..............................................................
        }
}
interface AgentEncapsulantMessages .....................................
  ......................................................................
{
        @Override
        default
        public void envoyer(String msg) {
          ..............................................................
        }
}
class AgentDecoupantMessagesPourProtocole1 .............................
  ......................................................................
{
  ......................................................................
}
class AgentDecoupantMessagesPourProtocole2 .............................
  ......................................................................
{
  ......................................................................
}
class AgentEncapsulantMessagesPourProtocole1 ...........................
  ......................................................................
{
  ......................................................................
}
class AgentEncapsulantMessagesPourProtocole2 ...........................
  ......................................................................
{
  ......................................................................
}

Agrégation avec délégation

On réalise les quatre combinaisons en factorisant la couche haute et celle basse.

Réaliser le schéma suivant dans le paquet td3.agregation. Suivre les commentaires ci-dessous.

medias/progMod15_td3_agregation.png

Agrégation avec délégation - Factorisation des deux couches

class AgentDecoupantMessages ...........................................
  ......................................................................
{
  // Attribut de type Canal et constructeur associé
  ......................................................................        
  ......................................................................
  ......................................................................
  ......................................................................
  ......................................................................
        @Override
        public void envoyer(String msg) {
          ..............................................................
        }
        @Override
        public void emettre(String msg) {
          // Délégation au canal
          ..............................................................
        }
}
class AgentEncapsulantMessages .........................................
  ......................................................................
{
  // Attribut de type Canal et constructeur associé
  ......................................................................        
  ......................................................................
  ......................................................................
  ......................................................................
  ......................................................................
        @Override
        public void envoyer(String msg) {
          ..............................................................
        }
        @Override
        public void emettre(String msg) {
          // Délégation au canal
          ..............................................................
        }
}

Test

Dans les trois paquets contenant les implémentations utilisant l'héritage, ajouter une classe de test, définie ainsi, puis tester les implémentations.

class Test {
        public static void main(String[] args) {
                AgentCommuniquant a = new AgentDecoupantMessagesPourProtocole1();
                a.envoyer("nul n'est censé ignorer les principes de modularité.");

                Agent b = new AgentDecoupantMessagesPourProtocole2();
                b.envoyer("nul n'est censé ignorer les principes de modularité.");

                a = new AgentEncapsulantMessagesPourProtocole1();
                a.envoyer("nul n'est censé ignorer les principes de modularité.");

                b = new AgentEncapsulantMessagesPourProtocole2();
                b.envoyer("nul n'est censé ignorer les principes de modularité.");
        }
}

Dans le paquet td3.agregation, réliser le même test.

class Test {
        public static void main(String[] args) {
                AgentCommuniquant a = ..................................
                  ......................................................
                a.envoyer("nul n'est censé ignorer les principes de modularité.");

                Agent b = ..............................................
                  ......................................................
                b.envoyer("nul n'est censé ignorer les principes de modularité.");

                a = ....................................................
                  ......................................................
                a.envoyer("nul n'est censé ignorer les principes de modularité.");

                b = ....................................................
                  ......................................................
                b.envoyer("nul n'est censé ignorer les principes de modularité.");
        }
}

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