Examen CNAM NFP121 – Tâches hiérarchiques en Java
Exercice 1 : Compréhension de l’architecture des tâches
L’architecture des tâches hiérarchiques utilise le patron de conception Composite.
- TacheComplexe : Composite (contient des sous-tâches)
- Tache : Composant (interface commune pour les tâches)
- TacheElementaire : Feuille (tâche sans sous-tâches)
Les méthodes ajouter et supprimer sont spécifiques au composite TacheComplexe.
Solution pour la classe TacheElementaire
Voici la classe TacheElementaire implémentant l’interface Tache :
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;
}
}
Exercice 2 : Définition d’une tâche complexe
2.1 Principal intérêt de la généricité
La généricité permet un contrôle de type à la compilation, évitant les erreurs lors de l’exécution.
2.2 Coût de la tâche tA
Le coût total de la tâche tA est 30 (10 + 20).
Solution pour la classe TacheComplexe
Voici l’implémentation de la classe TacheComplexe :
import java.util.Collection;
import java.util.ArrayList;
import java.util.Iterator;
public class TacheComplexe implements Tache, Iterable {
private String nom;
private Collection sousTaches;
public TacheComplexe(String nom) {
this.nom = nom;
this.sousTaches = new ArrayList();
}
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 iterator() {
return this.sousTaches.iterator();
}
}
Exercice 3 : Interface graphique pour définir une tâche complexe
3.1 Schéma de la fenêtre
La fenêtre contient :
- Un champ de texte pour le nom (à gauche)
- Un champ de texte pour le coût (à droite)
- Deux boutons en bas : Ajouter (à gauche) et Quitter (à droite)
3.2 Compléter la classe TacheComplexeSwing
Voici les ajouts nécessaires pour activer les boutons :
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class TacheComplexeSwing {
private TacheComplexe tache;
final JFrame fenetre = new JFrame("Nouvelle tâche");
final private JTextField valeurNom = new JTextField(10);
final private JTextField valeurCout = new JTextField(10);
final private JButton boutonAjouter = new JButton("Ajouter");
final private JButton boutonQuitter = new JButton("Quitter");
public TacheComplexeSwing(TacheComplexe tache) {
this.tache = tache;
Container c = fenetre.getContentPane();
c.setLayout(new BorderLayout());
JPanel informations = new JPanel(new GridLayout(2, 2));
informations.add(new JLabel("Nom :", SwingConstants.RIGHT));
informations.add(valeurNom);
informations.add(new JLabel("Coût :", SwingConstants.RIGHT));
informations.add(valeurCout);
c.add(informations, BorderLayout.CENTER);
JPanel boutons = new JPanel(new FlowLayout());
boutons.add(boutonAjouter);
boutons.add(boutonQuitter);
c.add(boutons, BorderLayout.SOUTH);
boutonQuitter.addActionListener(new ActionQuitter());
boutonAjouter.addActionListener(new ActionAjouter());
fenetre.pack();
fenetre.setVisible(true);
}
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));
valeurCout.setBackground(Color.WHITE); // Réinitialiser la couleur
System.out.println("Cout total = " + tache.getCout());
} catch (NumberFormatException e) {
valeurCout.setBackground(Color.RED);
}
}
}
private class ActionQuitter implements ActionListener {
public void actionPerformed(ActionEvent ev) {
fenetre.dispose();
}
}
public static void main(String[] args) {
new TacheComplexeSwing(new TacheComplexe("TestTacheComplexeSwing"));
}
}
Exercice 4 : Sauvegarde d’une tâche en XML
4.1 Contenu XML pour la tâche tA
<taches>
<tache>
<attribut nom="nom" valeur="A"/>
<attribut nom="cout" valeur="30"/>
<tache>
<attribut nom="nom" valeur="A1"/>
<attribut nom="cout" valeur="10"/>
</tache>
<tache>
<attribut nom="nom" valeur="A2"/>
<attribut nom="cout" valeur="20"/>
</tache>
</tache>
</taches>
4.2 Compléter la classe TacheJDom
import org.jdom.*;
import org.jdom.output.*;
import java.io.OutputStream;
import java.io.PrintStream;
import java.io.IOException;
import java.io.FileWriter;
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", "-//Exemple//DTD 1.0//"));
sortie.output(d, new FileWriter(nomFichier));
}
public Element ajouterAttribut(Element elt, String nom, String valeur) {
elt.addContent(new Element("attribut")
.setAttribute("nom", nom)
.setAttribute("valeur", valeur));
return elt;
}
public Element getElement(TacheComplexe tc) {
Element elt = new Element("tache");
elt = this.ajouterAttribut(elt, "nom", tc.getNom());
elt = this.ajouterAttribut(elt, "cout", "" + tc.getCout());
for (Tache t : tc) {
elt.addContent(getElement(t));
}
return elt;
}
public Element getElement(TacheElementaire te) {
Element elt = new Element("tache");
elt = this.ajouterAttribut(elt, "nom", te.getNom());
elt = this.ajouterAttribut(elt, "cout", "" + te.getCout());
return elt;
}
public Element getElement(Tache t) {
if (t instanceof TacheComplexe) {
return getElement((TacheComplexe) t);
} else {
return getElement((TacheElementaire) t);
}
}
}
Exercice 5 : Utilisation de SAX
Solution pour le gestionnaire SAX
import org.xml.sax.*;
import org.xml.sax.helpers.DefaultHandler;
class ProfondeurMaxHandler extends DefaultHandler {
private int level = 0;
private int max = 0;
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;
}
}
FAQ
Qu’est-ce que le patron Composite ?
Le patron Composite permet de traiter de manière uniforme des objets individuels et des compositions d’objets, en les représentant tous sous une interface commune.
Pourquoi utiliser la généricité en Java ?
La généricité garantit la sécurité des types à la compilation et évite les erreurs de cast lors de l’exécution.
Quelle est la différence entre TacheComplexe et TacheElementaire ?
TacheComplexe peut contenir d’autres tâches (Tache), tandis que TacheElementaire n’a pas de sous-tâches et représente une tâche simple.