Td5 + correction : le design pattern composite - design patt

IUT Villetaneuse – M3105 : Conception et Programmation Objet Avancées (2016/2017)

Correction TD5 : Le Design Pattern Composite

Nous utilisons le design pattern composite pour représenter et calculer des expressions arithmétiques contenant des additions, soustractions, multiplications et divisions.

Une expression arithmétique peut être représentée sous forme d’arborescence. Par exemple, l’expression (3 + 4) / (5 * (10 – 6)) correspond à l’arborescence suivante :

Figure 1 – Arborescence

Dans un premier temps, nous n’utilisons pas le design pattern composite.

Sur l’arborescence précédente, on observe qu’une opération possède deux types d’opérandes : les nombres (feuilles) et les opérations (nœuds). Par exemple, dans l’opération 5 * (10 – 6), la première opérande est le nombre 5 et la seconde est l’opération (10 – 6).

a) Compléter le diagramme des classes pour représenter les deux arguments des opérations

Le diagramme doit inclure les classes suivantes :

  • Nombre : classe concrète représentant un nombre avec un attribut valeurNombre.
  • Operation : classe abstraite avec deux attributs operande1 et operande2, tous deux de type Expression.

Un commentaire doit préciser qu’une opération a exactement deux opérandes.

b) Ajouter les méthodes valeur() et toString() aux classes

Les classes doivent implémenter :

  • valeur() : méthode retournant une valeur de type double.
  • toString() : méthode redéfinie pour afficher la représentation textuelle.

II. Design Pattern Composite

On introduit une classe Expression dont les classes Nombre et Operation héritent.

a) Modifier le diagramme avec le design pattern composite

La classe Expression devient la racine commune. Les méthodes getOperande1() et getOperande2() sont ajoutées avec un comportement par défaut (retour de null) pour les nombres.

b) Compléter le diagramme avec les spécifications suivantes

  • Nombre : attribut valeurNombre et constructeur initialisant ce dernier.
  • Expression : méthodes getOperande1() et getOperande2() retournant les opérandes (par défaut null).
  • Operation : constructeur initialisant les deux opérandes operande1 et operande2, et redéfinition des méthodes getOperande1() et getOperande2().

c) Implémentation des méthodes valeur() et toString() pour la classe Addition

valeur() :

public double valeur() {
    return this.getOperande1().valeur() + this.getOperande2().valeur();
}

toString() :

public String toString() {
    return "(" + this.getOperande1() + " + " + this.getOperande2() + ")";
}

III. Traduction en Java et Tests

Voici le code Java correspondant au design pattern composite pour les expressions arithmétiques :

/**
 * Gestion d'une expression arithmétique
 */
public abstract class Expression {
    public Expression getOperande1() {
        return null;
    }

    public Expression getOperande2() {
        return null;
    }

    public abstract double valeur();
    public abstract String toString();
}

public class Nombre extends Expression {
    private double valeurNombre;

    public Nombre(double uneValeur) {
        this.valeurNombre = uneValeur;
    }

    public double valeur() {
        return this.valeurNombre;
    }

    public String toString() {
        return Double.toString(this.valeurNombre);
    }
}

public abstract class Operation extends Expression {
    private Expression operande1;
    private Expression operande2;

    public Operation(Expression op1, Expression op2) {
        this.operande1 = op1;
        this.operande2 = op2;
    }

    public Expression getOperande1() {
        return this.operande1;
    }

    public Expression getOperande2() {
        return this.operande2;
    }
}

public class Addition extends Operation {
    public Addition(Expression op1, Expression op2) {
        super(op1, op2);
    }

    public double valeur() {
        return this.getOperande1().valeur() + this.getOperande2().valeur();
    }

    public String toString() {
        return "(" + this.getOperande1() + " + " + this.getOperande2() + ")";
    }
}

public class Soustraction extends Operation {
    public Soustraction(Expression op1, Expression op2) {
        super(op1, op2);
    }

    public double valeur() {
        return this.getOperande1().valeur() - this.getOperande2().valeur();
    }

    public String toString() {
        return "(" + this.getOperande1() + " - " + this.getOperande2() + ")";
    }
}

public class Multiplication extends Operation {
    public Multiplication(Expression op1, Expression op2) {
        super(op1, op2);
    }

    public double valeur() {
        return this.getOperande1().valeur() * this.getOperande2().valeur();
    }

    public String toString() {
        return "(" + this.getOperande1() + " * " + this.getOperande2() + ")";
    }
}

public class Division extends Operation {
    public Division(Expression op1, Expression op2) {
        super(op1, op2);
    }

    public double valeur() {
        return this.getOperande1().valeur() / this.getOperande2().valeur();
    }

    public String toString() {
        return "(" + this.getOperande1() + " / " + this.getOperande2() + ")";
    }
}

public class Calculatrice {
    public static void main(String[] args) {
        Expression trois = new Nombre(3);
        Expression quatre = new Nombre(4);
        Expression cinq = new Nombre(5);
        Expression six = new Nombre(6);
        Expression dix = new Nombre(10);

        Expression s = new Soustraction(dix, six);
        System.out.println(s + " = " + s.valeur());

        Expression a = new Addition(trois, quatre);
        System.out.println(a + " = " + a.valeur());

        Expression m = new Multiplication(cinq, s);
        System.out.println(m + " = " + m.valeur());

        Expression d = new Division(a, m);
        System.out.println(d + " = " + d.valeur());
    }
}

FAQ

1. Pourquoi utiliser le design pattern composite pour les expressions arithmétiques ?

Le design pattern composite permet de traiter uniformément les objets simples (nombres) et complexes (opérations) comme des éléments d’une même hiérarchie. Cela simplifie la manipulation et le calcul des expressions, car toutes les classes héritent d’une interface commune (Expression).

2. Comment fonctionne la méthode valeur() dans la classe Nombre ?

La méthode valeur() de la classe Nombre retourne simplement la valeur stockée dans l’attribut valeurNombre, car un nombre est une expression simple dont la valeur est déjà définie.

3. Pourquoi les méthodes getOperande1() et getOperande2() retournent-elles null par défaut dans Expression ?

Dans le design pattern composite, les nombres n’ont pas d’opérandes. Les méthodes retournent null par défaut pour indiquer qu’elles ne sont pas applicables aux objets simples (Nombre). Les opérations, elles, redéfinissent ces méthodes pour retourner leurs opérandes.

Cela peut vous intéresser :

Partagez vos remarques, questions , propositions d'amélioration ou d'autres cours à ajouter dans notre site

Enregistrer un commentaire (0)
Plus récente Plus ancienne