Corrigé de l'examen de mai 2001

Partie 1

Code complet : Action.java, FArbre.java

Partie 2

  1. Il suffit de créer une interface reprenant les méthodes communes au deux classes, ce qui correspond aux méthodes de la classe ArbreImp ne nécessitant pas d'effet de bord sur la structure de données : Arbre.java.
  2.  ArbreImp.java. Il faut de plus déclarer que Farbre implémente Arbre en modifiant la première ligne de cette classe par

  3. public class FArbre implements Arbre {
Code complet : Action.java, Arbre.java, ArbreImp.java, FArbre.java

Partie 3

  1. Variable.java
  2. ArbreSyntaxique.java

  3. Code complet de la version intermédiaire : Action.java, Arbre.java, ArbreImp.java, ArbreSyntaxique.java, ErreurSyntaxiqueException.java, Operateur.java, OperateurExistantException.java, OperateurInexistantException.java, Variable.java
  4.     public void miseAJour() {

  5.         IOperateur op = (IOperateur) data();
            int [] operandes = new int[op.arite()];
            int i = 0;

            for (Iterator it = fils(); it.hasNext();) {
                operandes[i++] = ((ArbreSyntaxique) it.next()).valeur;
            }
            valeur = op.evaluer(operandes);
            if (pere() != null) {
                ((ArbreSyntaxique) pere()).miseAJour();
            }
        }

  6. L'héritage multiple est impossible en Java.

  7. La méthode setChanged() étant protected, elle n'est pas utilisable depuis une classe n'héritant pas de java.util.Observable et n'appartenant pas au paquetage java.util. Par conséquent, parmi les classes hors java.util, seuls les instances de celles héritant d'Observable peuvent passer à un état "modifié".
  8. IOperateur.java, IVariable.java.

  9. La classe Operateur doit être déclarée comme implémentant IOperateur :
    public abstract class Operateur implements IOperateur {
    La méthode de classe Operateur.operateur(String nom) doit être déclarée comme renvoyant une instance de IOperateur :
    public static IOperateur operateur(String nom)
    La classe Variable doit être déclarée comme implémentant IVariable :
    public class Variable extends Operateur implements IVariable {
  10.     static void substituerOperateur(String nom, IOperateur op)

  11.         throws OperateurInexistantException
        {
            IOperateur op2 = (IOperateur) ops.get(nom);
            if (op2 == null) {
                throw new OperateurInexistantException(nom);
            }
            ops.put(nom, op);
        }

        public int arite() {
            return arite;
        }
    Cette méthode est indispensable car la classe décorant un opérateur va renvoyer une instance d'IOperateur ayant une autre référence que celle passée en paramètre. En d'autres termes, un décorateur ne préserve pas les références, l'instance décorée ayant une référence autre que l'instance à décorer.
    Pour limiter l'usage de cette méthode, il est nécessaire de regrouper toutes ces classes dans un paquetage et limiter l'accès de la méthode substituerOperateur(String nom, IOperateur op) aux classes de ce paquetage (accessibilité par défaut).

  12. ArbreSyntaxique.java

  13. Code complet de la version intermédiaire : Action.java, Arbre.java, ArbreImp.java, ArbreSyntaxique.java, ErreurSyntaxiqueException.java, IOperateur.java, IVariable.java, Operateur.java, OperateurExistantException.java, OperateurInexistantException.java, Variable.java, VariableObservable.java
  14. Une façon simple de procéder est d'écrire une classe ArbreSyntaxiqueSynchronise qui hérite d'ArbreSyntaxique et qui surcharge les méthodes  valeur() et miseAJour()  en les déclarant synchronized. La version de miseAJour() donnée ici appelle directement la méthode miseAJour()de la classe mère, ce qui n'est pas le plus efficace. Mais il faudrait alors soit accepter de la duplication de code, soit découper la méthode de la classe mère ArbreSyntaxique et déclarer certaines parties protected de façon à les remplacer dans ArbreSyntaxiqueSynchronise.
    Code complet : Action.java, Arbre.java, ArbreImp.java, ArbreSyntaxique.java, ArbreSyntaxiqueSynchronise.java, ErreurSyntaxiqueException.java, IOperateur.java, IVariable.java, Operateur.java, OperateurExistantException.java, OperateurInexistantException.java, Variable.java, VariableObservable.java, VariableThread.java