Examen NFP121

Ce document présente un examen de programmation orientée objet et XML, axé sur la conception et la manipulation de tâches hiérarchiques en Java, ainsi que sur la gestion de fichiers XML. Il évalue les compétences en modélisation, codage Java, utilisation d’interfaces graphiques Swing, génération de fichiers XML avec JDom, et traitement SAX.

D'après le document Examen NFP121

Cet article a été rédigé automatiquement à partir du document source, puis vérifié avant publication.

Document source

Examen NFP121

Programming, Math, etc. · PDF · 8 pages · 2008

Afficher l'aperçu du document

Consulter le document original →

Ce document présente un examen de programmation orientée objet et XML, axé sur la conception et la manipulation de tâches hiérarchiques en Java, ainsi que sur la gestion de fichiers XML. Il évalue les compétences en modélisation, codage Java, utilisation d’interfaces graphiques Swing, génération de fichiers XML avec JDom, et traitement SAX.

Exercice 1 : Compréhension de l’architecture des tâches

Il s’agit d’identifier les patrons de conception utilisés dans l’architecture des tâches, puis d’implémenter la classe TacheElementaire conforme à l’interface Tache.

1.1 Identifier les patrons de conception

L’architecture donnée présente une hiérarchie où une tâche est soit élémentaire, soit complexe (composée de sous-tâches). Ce modèle correspond au patron Composite :

  • Composant : interface Tache
  • Feuille : TacheElementaire
  • Composite : TacheComplexe

Les méthodes ajouter(Tache) et supprimer(Tache) sont définies uniquement sur le composite, ce qui est conforme au patron Composite classique.

Réponse : Le patron Composite est utilisé.

1.2 Écrire la classe TacheElementaire en Java

La classe doit implémenter l’interface Tache, fournir un constructeur avec nom et coût, et implémenter les méthodes getNom() et getCout().

public class TacheElementaire implements Tache {
    private String nom;
    private int cout;

    public TacheElementaire(String nom, int cout) {
        this.nom = nom;
        this.cout = cout;
    }

    public String getNom() {
        return this.nom;
    }

    public int getCout() {
        return this.cout;
    }
}

Réponse : La classe TacheElementaire est définie comme ci-dessus.

Exercice 2 : Définition d’une tâche complexe

On étudie la classe TacheComplexe, qui stocke ses sous-tâches dans une Collection générique et implémente Iterable pour permettre leur parcours.

2.1 Intérêt principal de la généricité

La généricité permet au compilateur d’effectuer un contrôle de type à la compilation, évitant ainsi les erreurs de type au moment de l’exécution.

Réponse : Le principal intérêt est le contrôle de type réalisé par le compilateur.

2.2 Calcul du coût de la tâche tA

La tâche tA est créée avec deux sous-tâches élémentaires A1 (coût 10) et A2 (coût 20). Le coût d’une tâche complexe est la somme des coûts de ses sous-tâches.

Donc, coût de tA = 10 + 20 = 30.

Réponse : Le coût de tA est 30.

2.3 Écrire la classe TacheComplexe en Java

La classe doit implémenter l’interface Tache et Iterable<Tache>, stocker les sous-tâches dans une Collection<Tache>, et fournir les méthodes ajouter, supprimer, getNom, getCout, et iterator.

import java.util.Collection;
import java.util.ArrayList;
import java.util.Iterator;

public class TacheComplexe implements Tache, Iterable<Tache> {
    private String nom;
    private Collection<Tache> sousTaches;

    public TacheComplexe(String nom) {
        this.nom = nom;
        this.sousTaches = new ArrayList<Tache>();
    }

    public void ajouter(Tache tache) {
        this.sousTaches.add(tache);
    }

    public void supprimer(Tache tache) {
        this.sousTaches.remove(tache);
    }

    public String getNom() {
        return this.nom;
    }

    public int getCout() {
        int result = 0;
        for (Tache t : sousTaches) {
            result += t.getCout();
        }
        return result;
    }

    public Iterator<Tache> iterator() {
        return this.sousTaches.iterator();
    }
}

Réponse : La classe TacheComplexe est définie comme ci-dessus.

Exercice 3 : Interface graphique pour définir une tâche complexe

Il s’agit de dessiner la fenêtre Swing minimale affichée par la classe TacheComplexeSwing, puis de compléter le code pour rendre les boutons Ajouter et Quitter fonctionnels.

3.1 Description de la fenêtre affichée

La fenêtre contient :

  • Un panneau central avec une grille 2x2 comprenant :
    • Une étiquette "Nom :" alignée à droite, suivie d’un champ texte pour saisir le nom (valeurNom).
    • Une étiquette "Coût :" alignée à droite, suivie d’un champ texte pour saisir le coût (valeurCout).
  • Un panneau en bas avec deux boutons : "Ajouter" et "Quitter".

La fenêtre porte le titre "Nouvelle tâche".

3.2 Compléter la classe pour activer les boutons

Le bouton Quitter doit fermer la fenêtre. Le bouton Ajouter doit :

  • Récupérer le texte des champs valeurNom et valeurCout.
  • Convertir valeurCout en entier avec Integer.parseInt.
  • En cas d’exception NumberFormatException, colorer le fond du champ valeurCout en rouge.
  • Sinon, créer une nouvelle TacheElementaire avec ces valeurs et l’ajouter à la tâche complexe.
  • Afficher dans la console le coût total de la tâche complexe mise à jour.

Code à insérer dans la classe TacheComplexeSwing :

private class ActionAjouter implements ActionListener {
    public void actionPerformed(ActionEvent ev) {
        try {
            String nom = valeurNom.getText();
            int cout = Integer.parseInt(valeurCout.getText());
            tache.ajouter(new TacheElementaire(nom, cout));
            System.out.println("cout total = " + tache.getCout());
            valeurCout.setBackground(Color.WHITE); // Remise à blanc si succès
        } catch (NumberFormatException e) {
            valeurCout.setBackground(Color.RED);
        }
    }
}

private class ActionQuitter implements ActionListener {
    public void actionPerformed(ActionEvent ev) {
        System.out.println("Appui sur Quitter...");
        fenetre.dispose();
    }
}

Réponse : Les classes ActionAjouter et ActionQuitter sont définies comme ci-dessus, rendant les boutons fonctionnels.

Exercice 4 : Sauvegarde d’une tâche en XML

On étudie la représentation XML d’une tâche complexe selon une DTD donnée, puis la génération de ce XML avec JDom.

4.1 Contenu XML correspondant à la tâche tA

La tâche tA a pour nom "A" et coût 30, avec deux sous-tâches A1 (10) et A2 (20). Le fichier XML (sans l’entête) est :

<tache>
  <attribut nom="nom" valeur="A" />
  <attribut nom="cout" valeur="30" />
  <tache>
    <attribut nom="nom" valeur="A2" />
    <attribut nom="cout" valeur="20" />
  </tache>
  <tache>
    <attribut nom="nom" valeur="A1" />
    <attribut nom="cout" valeur="10" />
  </tache>
</tache>

Réponse : Le contenu XML est celui présenté ci-dessus.

4.2 Compléter la classe TacheJDom pour générer le fichier XML

La classe utilise JDom pour construire un document XML valide selon la DTD. La méthode printToXML crée la racine <taches>, ajoute l’élément correspondant à la tâche passée, puis écrit le fichier.

La méthode ajouterAttibut ajoute un élément <attribut> avec les attributs nom et valeur.

Les méthodes getElement sont surchargées pour TacheComplexe, TacheElementaire et Tache, construisant récursivement l’arbre XML.

import org.jdom.*;
import org.jdom.output.*;
import java.io.FileWriter;
import java.io.IOException;

public class TacheJDom {
    private XMLOutputter sortie = new XMLOutputter(Format.getPrettyFormat());

    public void printToXML(Tache t, String nomFichier) throws IOException {
        Element racine = new Element("taches");
        racine.addContent(this.getElement(t));
        Document d = new Document(racine, new DocType("taches", "taches.dtd"));
        sortie.output(d, new FileWriter(nomFichier));
    }

    public Element ajouterAttibut(Element e, String nom, String valeur) {
        Element attribut = new Element("attribut");
        attribut.setAttribute("nom", nom);
        attribut.setAttribute("valeur", valeur);
        e.addContent(attribut);
        return e;
    }

    public Element getElement(TacheComplexe tc) {
        Element elt = new Element("tache");
        this.ajouterAttibut(elt, "nom", tc.getNom());
        this.ajouterAttibut(elt, "cout", "" + tc.getCout());
        for (Tache t : tc) {
            elt.addContent(getElement(t));
        }
        return elt;
    }

    public Element getElement(TacheElementaire te) {
        Element elt = new Element("tache");
        this.ajouterAttibut(elt, "nom", te.getNom());
        this.ajouterAttibut(elt, "cout", "" + te.getCout());
        return elt;
    }

    public Element getElement(Tache t) {
        if (t instanceof TacheComplexe) {
            return getElement((TacheComplexe) t);
        } else {
            return getElement((TacheElementaire) t);
        }
    }
}

Réponse : La classe TacheJDom est complétée comme ci-dessus pour générer un fichier XML valide.

4.3 Patrons de conception pour la génération XML

Deux solutions sont proposées :

  • Le patron Visiteur : permettrait de séparer la logique de génération XML de la structure des tâches en visitant les classes TacheElementaire et TacheComplexe.
  • Méthode abstraite getElement() : définie dans l’interface Tache et redéfinie dans chaque sous-classe, pour générer directement l’élément XML correspondant.

Réponse : Les patrons Visiteur ou méthode abstraite redéfinie sont adaptés pour générer le XML.

Exercice 5 : Utilisation de SaX

Il s’agit d’écrire un gestionnaire SAX qui calcule la profondeur maximale d’imbrication des éléments <tache> dans un fichier XML conforme à la DTD.

Le principe est de compter le nombre d’éléments <tache> ouverts non fermés (niveau courant), et de mémoriser la profondeur maximale atteinte.

Code partiel et complété :

import org.xml.sax.*;
import org.xml.sax.helpers.*;

class ProfondeurMaxHandler extends DefaultHandler {
    private int level;
    private int max;

    public void startDocument() {
        this.level = 0;
        this.max = 0;
    }

    public void startElement(String uriEspaceNom, String nom, String nomQualifie, Attributes attributs) throws SAXException {
        if (nomQualifie.equals("tache")) {
            this.level++;
            if (this.level > this.max) {
                this.max = this.level;
            }
        }
    }

    public void endElement(String uriEspaceNom, String nom, String nomQualifie) throws SAXException {
        if (nomQualifie.equals("tache")) {
            this.level--;
        }
    }

    public int getProfondeurMax() {
        return this.max;
    }
}

Appliqué au fichier XML de la tâche tA (profondeur 2), ce gestionnaire retourne 2.

Réponse : Le gestionnaire SAX est défini comme ci-dessus et calcule correctement la profondeur maximale.

Méthode

Ce sujet récompense une compréhension précise des patrons de conception, notamment Composite et Visiteur, ainsi que la capacité à coder en Java des classes conformes à des interfaces données.

Il valorise également la maîtrise des collections génériques, de l’interface Iterable, et des exceptions en Java.

La partie interface graphique teste la gestion des événements Swing et la validation des saisies utilisateur.

La génération XML avec JDom exige une bonne organisation du code et la récursivité pour refléter la hiérarchie des tâches.

Enfin, la manipulation SAX demande de bien comprendre le cycle de vie des événements XML et la gestion d’un compteur d’imbrication.

Les erreurs fréquentes à éviter sont :

  • Ne pas respecter la structure Composite (ex : ajouter/supprimer sur les feuilles).
  • Oublier le contrôle de type avec la généricité.
  • Ne pas gérer les exceptions lors de la conversion de chaînes en entiers.
  • Ne pas remettre la couleur de fond à blanc après une erreur corrigée.
  • Oublier d’implémenter Iterable pour TacheComplexe.
  • Ne pas générer un XML conforme à la DTD.
  • Dans SAX, ne pas décrémenter le niveau à la fermeture d’une balise.

Une rédaction claire, un code propre et des justifications précises sont indispensables pour obtenir la meilleure note.

Partager

Commentaires

Aucun commentaire pour le moment. Posez la première question.

Les commentaires sont relus avant publication. Votre e-mail n'est jamais affiché.

← Toutes les révisions