Examen NFP121

Programming, Math, etc. · exam

Voir tous les documents en programmation

CNAM

NFP121

EXAMEN 1

29/01/2008 (Séance 14)

Examen (avec document) Corrigé

Préambule : Répondre de manière concise et précise aux questions. Ne pas mettre de commentaires de documentation sauf s’ils sont nécessaires à la compréhension. Barème indicatif :

exercice points

1 3

2 4

3 5

4 5

5 3

L’objectif de ces exercices est de définir des tâches hiérarchiques et de les exploiter de diffé-

rentes manières.

Exercice 1 : Compréhension de l’architecture des tâches L’architecture des tâches est donnée à la figure 1 où le détail des classes TacheElementaire et TacheComplexe n’est pas donné. Une tâche est caractérisée par un nom et un coût. Une tâche est soit une tâche élémentaire, soit une tâche complexe qui est alors composée de sous-tâches. Il est ainsi possible d’ajouter une sous-tâche à une tâche complexe, ajouter(Tache) ou de supprimer une sous-tâche, supprimer(Tache). Le coût d’une tâche complexe est la somme des coûts des tâches qui la composent.

«interface» Tache

getNom(): String getCout(): int

0..* sousTaches

TacheElementaire

TacheComplexe

FIG. 1 – Architecture des tâches hiérarchiques

1.1 Indiquer le ou les patrons de conception utilisés dans cette architecture. Solution : Composite : La tâche complexe est le composite, Tache est le composant et Ta- cheElementaire est la feuille. Notons que les objets ajouter et supprimer ne sont ici que sur le composite et pas sur le composant. 1.2 Le listing 1 donne le code de l’interface Tache.

Écrire en Java la classe TacheElementaire qui est une réalisation de l’interface Tache.

EXAMEN 1

1/8

NFP121

Examen (avec document)

Listing 1 – L’interface Tache

/** Obtenir le nom de la tâche. */ String getNom();

1 public interface Tache { 2 3 4 5 6 7 }

/** Obtenir le coût de la tâche. */ int getCout();

Solution :

public TacheElementaire(String nom, int cout) {

}

this.nom = nom; this.cout = cout;

private String nom; private int cout;

1 public class TacheElementaire implements Tache { 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 }

public String getNom() { return this.nom;

public int getCout() {

return this.cout;

}

}

Exercice 2 : Définition d’une tâche complexe Nous nous intéressons maintenant à la classe TacheComplexe, en particulier à sa relation avec l’interface Tache. Une tâche complexe est composée d’un nombre quelconque de tâches. On décide d’utiliser l’interface java.util.Collection pour stocker les sous-tâches. On l’utilisera bien entendu dans sa version générique.

Comme on souhaite pouvoir parcourir toutes les sous-tâches d’une tâche complexe, la classe

TacheComplexe réalise l’interface java.lang.Iterable. 2.1 Indiquer quel est le principal intérêt de la généricité. Solution : Le contrôle de type réalisé par le compilateur. 2.2 Indiquer quel est le coût de la tâche tA construite comme indiqué dans le listing 2.

Listing 2 – La classe TestTache1

public static void main(String[] args) {

TacheComplexe tA = new TacheComplexe("A"); tA.ajouter(new TacheElementaire("A1", 10)); tA.ajouter(new TacheElementaire("A2", 20));

1 public class TestTache1 { 2 3 4 5 6 7 8 9 }

}

Publicité

System.out.println("Cout de tA = " + tA.getCout());

EXAMEN 1

2/8

NFP121

Examen (avec document)

Solution : 30 2.3 Écrire en Java la classe TacheComplexe. Solution :

}

}

public TacheComplexe(String nom) {

public void supprimer(Tache tache) {

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

private Collection<Tache> sousTaches; private String nom;

this.nom = nom; this.sousTaches = new ArrayList<Tache>();

1 import java.util.Collection; 2 import java.util.ArrayList; 3 import java.util.Iterator; 4 5 public class TacheComplexe implements Tache, Iterable<Tache> { 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 }

public int getCout() { int result = 0; for (Tache t : sousTaches) {

public String getNom() { return this.nom;

public Iterator<Tache> iterator() {

return this.sousTaches.iterator();

} return result;

this.sousTaches.remove(tache);

result += t.getCout();

}

}

}

}

Exercice 3 : Interface graphique pour définir une tâche complexe Nous définissons maintenant une interface graphique en Swing minimale qui permet d’ajouter de nouvelles sous-tâches à une tâche complexe. Le code partiel de cette classe est donné au listing 3. 3.1 Dessiner la fenêtre (et les composants graphiques qu’elle contient) telle qu’elle est affichée quand cette classe est exécutée. Solution :

EXAMEN 1

3/8

NFP121

Examen (avec document)

3.2 Compléter cette classe pour que les boutons Ajouter et Quitter deviennent actifs. Le bou- ton Quitter ferme la fenêtre. Le bouton Ajouter ajoute une nouvelle sous-tâche à la tâche com- plexe passée en paramètre du constructeur de cette classe. Le nom et le coût de cette sous- tâche sont, bien entendu, saisis par l’utilisateur dans les zones de saisie prévues, valeurNom et valeurCout. Dans le cas où l’utilisateur saisit une information qui n’est pas un entier pour saisir le coût, on signalera l’erreur en mettant la couleur de fond de la zone de saisie correspondante en rouge (setBackground(Color.RED)). On rappelle que la méthode Integer.parseInt(String) renvoie l’entier correspondant à la chaîne de caractère passé en paramètre. Cette méthode lève l’exception NumberFormatException si la chaîne ne correspond pas à un entier. Remarque : On pourra mettre des numéros sur le listing 3 pour indiquer où du code doit être ajouté, le code correspondant étant écrit sur la copie, précédé du même numéro.

Listing 3 – La classe 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);

1 import javax.swing.*; 2 import java.awt.*; 3 import java.awt.event.*; 4 5 public class TacheComplexeSwing { 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32

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());

EXAMEN 1

4/8

NFP121

Examen (avec document)

33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 }

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)); System.out.println("cout total = " + tache.getCout());

} catch (NumberFormatException e) {

Publicité

valeurCout.setBackground(Color.RED);

}

}

}

private class ActionQuitter implements ActionListener {

public void actionPerformed(ActionEvent ev) {

System.out.println("Appui sur Quitter..."); fenetre.dispose();

}

}

public static void main(String[] args) {

new TacheComplexeSwing(new TacheComplexe("Test TacheComplexeSwing"));

}

Exercice 4 : Sauvegarde d’une tâche en XML Intéressons nous maintenant à la sauvegarde d’une tâche sous la forme d’un fichier XML dont la DTD est donnée au listing 4

Listing 4 – La DTD pour représenter une tâche

1 <?xml version="1.0" encoding="UTF-8"?> 2 3 <!ELEMENT taches (tache*)> 4 <!ELEMENT tache (attribut*, tache*)> 5 <!ELEMENT attribut EMPTY> 6 <!ATTLIST attribut 7 8

nom valeur CDATA #REQUIRED>

CDATA #REQUIRED

EXAMEN 1

5/8

NFP121

Examen (avec document)

4.1 Donner le contenu du fichier XML qui correspond à la tâche tA construite dans le listing 2. Ne pas donner l’entête de ce fichier XML. Solution :

<tache>

<attribut nom="nom" valeur="A" /> <attribut nom="cout" valeur="30" /> <tache>

1 <?xml version="1.0" encoding="UTF-8"?> 2 <!DOCTYPE taches SYSTEM "taches.dtd"> 3 4 <taches> 5 6 7 8 9 10 11 12 13 14 15 16 17 </taches>

<attribut nom="nom" valeur="A2" /> <attribut nom="cout" valeur="20" />

<attribut nom="nom" valeur="A1" /> <attribut nom="cout" valeur="10" />

</tache> <tache>

</tache>

</tache>

4.2 Compléter la classe TacheJDom pour engendrer le fichier XML représentant une tâche. Ce fichier devra être valide par rapport à la DTD du listing 4. On ne modifiera aucune des interfaces ou classes Tache, TacheElementaire et TacheComplexe.

Listing 5 – La classe TacheJDom

1 import org.jdom.*; 2 import org.jdom.output.*; 3 import java.io.OutputStream; 4 import java.io.PrintStream; 5 import java.io.IOException; 6 import java.io.FileWriter; 7 8 public class TacheJDom { 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27

return e.addContent(

}

}

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) {

new Element("attribut")

.setAttribute("nom", nom) .setAttribute("valeur", valeur));

EXAMEN 1

6/8

NFP121

Examen (avec document)

/** Construire l’élément correspondant à la tâche complexe tc. */ 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));

Publicité

} return elt;

}

/** Construire l’élément correspondant à la tâche élémentaire te. */ public Element getElement(TacheElementaire te) {

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

}

/** Construire l’élément correspondant à la tâche t. */ public Element getElement(Tache t) {

if (t instanceof TacheComplexe) {

return getElement((TacheComplexe) t);

} else {

return getElement((TacheElementaire) t);

}

}

28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 }

4.3 Indiquer les patrons de conception qui auraient pu être utilisés pour engendrer le fichier XML. Il est possible de modifier les interfaces ou classes Tache, TacheElementaire et Tache- Complexe. Solution : Le visiteur. Le visiteur permettrait alors de visiter les classes TacheElementaire et TacheComplexe.

Une autre solution consisterait à définir la méthode getElement() comme abstraite sur Tache

et, bien sûr, redéfinie sur les sous-classes.

Exercice 5 : Utilisation de SaX Étant donné, un fichier XML valide vis-à-vis de la DTD du listing 4, écrire un gestionnaire SaX (ContentHandler ou DefaultHandler) qui affiche le niveau d’imbrication de la tâche la plus interne. Appliqué sur le fichier correspondant à la tâche tA du listing 2, le résultat doit être 2. Indication : On pourra compter le nombre de balises ouvrantes <tache> non fermées. Solution :

1 import org.xml.sax.*;

EXAMEN 1

7/8

NFP121

Examen (avec document)

public void startElement(String uriEspaceNom, String nom,

String nomQualifie, Attributes attributs) throws SAXException {

}

private int level, max;

public void startDocument() {

this.level = 0; this.max = 0;

if (nomQualifie.equals("tache")) {

this.level++; if (this.level > this.max) {

2 import org.xml.sax.helpers.*; 3 4 class ProfondeurMaxHandler extends DefaultHandler { 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 }

if (nomQualifie.equals("tache")) {

public int getProfondeurMax() {

this.max = this.level;

return this.max;

this.level--;

}

}

}

}

}

}

public void endElement(String uriEspaceNom, String nom,

String nomQualifie) throws SAXException {

EXAMEN 1

8/8