• Aucun résultat trouvé

NFP121 Programmation avancée

N/A
N/A
Protected

Academic year: 2022

Partager "NFP121 Programmation avancée"

Copied!
14
0
0

Texte intégral

(1)

NFP121

Programmation avancée Session de Avril 2011-durée : 2 heures

Tous documents papiers autorisés

Cnam / Paris Sommaire :

Question 1 (4 points) : Une propriété

Question 2 (6 points) : Une liste de propriétés

Question 3 (6 points) : Sérialisation de propriétés en XML Question 4 (4 points) : Interface graphique Swing et évènements

Question1 (4 points) : Une propriété sur des objets

L’objectif est de définir et vérifier certaines propriétés sur des objets. Ces propriétés sont vraies ou fausses et portent sur des objets de types quelconques. Le type de l’objet est générique (<E>) et la propriété est définie par l’interface PropriétéI<E>.

L’architecture retenue des classes pour cette question est représentée par le diagramme, en notation BlueJ/UML,

ci-dessous. Ces classes contiennent un exemple simple sur les propriétés des nombres (NombrePair,

NombrePremier, NombreImpair), et sur les propriétés attendues d’une classe, comme la première lettre du nom de

la classe en Majuscule (NomEnMajuscule) et l’existence d’une méthode (MéthodeExiste) au sein de cette classe.

(2)

L’interface PropriétéI contient les opérations suivantes :

package question1 ;

public interface PropriétéI<E>{ // <E> le type de l’objet

String toString(); // l'objectif, l'intitulé de la propriété boolean estSatisfaite(E e); // la propriété est-elle vérifiée, satisfaite ? }

La classe NombrePair est un exemple de définition d’une propriété sur les nombres :

public class NombrePair implements PropriétéI<Integer>{

public String toString(){ // l'intitulé de la propriété return "nombre pair";

}

public boolean estSatisfaite(Integer i){

return i % 2 == 0; // la propriété est-elle vérifiée, satisfaite ? }

// equals et hashcode sont fournies }

Une méthode extraite de la classe de tests unitaires TestUnitaires :

public void test1(){

PropriétéI<Integer> p = new NombrePair();

assertTrue(p.toString(), p.estSatisfaite(4)); // 4 est pair ! assertFalse(p.toString(), p.estSatisfaite(3)); // 3 ne l’est pas … }

Sur le diagramme des classes, NomEnMajuscule et MéthodeExiste sont deux propriétés d’une classe, la première propriété est satisfaite si la première lettre du nom de la classe est une majuscule et la seconde propriété est satisfaite si la méthode avec ce nom et ces paramètres existe dans cette classe.

Les trois méthodes de la classe de tests unitaires sont à lire attentivement avant de répondre à cette question:

public void test2(){

PropriétéI<Class<?>> p = new NomEnMajuscule();

assertTrue(p.estSatisfaite(NombrePair.class));

assertTrue(p.estSatisfaite(TestsUnitaires.class));

}

public void test3(){

PropriétéI<Class<?>> p = new MéthodeExiste("add",Object.class);

// add(Object) doit exister dans ces 2 classes

assertTrue(p.estSatisfaite(java.util.ArrayList.class));

assertTrue(p.estSatisfaite(java.util.LinkedList.class));

// add(int, Object) doit exister dans cette classe

p = new MéthodeExiste("add",Integer.TYPE,Object.class);

assertTrue(p.estSatisfaite(java.util.ArrayList.class));

// note : ces deux syntaxes sont équivalentes, Class<?>… t, t est un tableau p = new MéthodeExiste("add",Integer.TYPE,Object.class);

p = new MéthodeExiste("add",new Class<?>[]{Integer.TYPE,Object.class});

(3)

}

public void test4(){

PropriétéI<Class<?>> p = new NomEnMajuscule();

String attendue = "le nom de la classe commence par une Majuscule";

assertTrue(p.toString().equals(attendue));

}

public void test5(){

PropriétéI<Class<?>> p = new MéthodeExiste("add",Object.class);

String attendue = "la méthode add(java.lang.Object) de la classe existe-t-elle ?";

assertTrue(p.toString().equals(attendue));

p = new MéthodeExiste("add",Integer.TYPE,Object.class);

attendue = "la méthode add(int, java.lang.Object) de la classe existe-t-elle ?";

assertTrue(p.toString().equals(attendue));

}

Question1-1)

Ecrire une implémentation complète de la classe NomEnMajuscule. Cette propriété est satisfaite si la première lettre du nom d’une classe est en majuscule. La méthode toString() associée doit vérifier les assertions présentes dans la méthode test4. (Les méthodes equals et hashCode sont fournies).

package question1;

public class NomEnMajuscule implements PropriétéI<Class<?>>{

public String toString(){

return "le nom de la classe commence par une Majuscule";

}

public boolean estSatisfaite(Class<?> classe){

char initiale = classe.getSimpleName().charAt(0);

return initiale >='A' && initiale <='Z';

}

public boolean equals(Object obj){

return obj.getClass() == this.getClass();

}

public int hashCode(){

return this.getClass().getName().hashCode();

} }

Question1-2)

Ecrire une implémentation complète de la classe MéthodeExiste. Cette propriété est satisfaite si la méthode avec ce nom et ces paramètres existe dans cette classe. La méthode toString() associée doit vérifier les assertions

présentes dans la méthode test5. (Les méthodes equals et hashCode sont fournies).

(4)

package question1;

public class MéthodeExiste implements PropriétéI<Class<?>>{

private String nomDeLaMéthode;

private Class<?>[] typeDesParamètres;

public MéthodeExiste(String nomDeLaMéthode, Class<?>... typeDesParamètres){

this.nomDeLaMéthode = nomDeLaMéthode;

this.typeDesParamètres = typeDesParamètres;

}

public String nomDeLaMéthode(){ return nomDeLaMéthode;}

public Class<?>[] typeDesParamètres(){ return typeDesParamètres;}

public String toString(){

return "la méthode " + nomDeLaMéthode() + "(" + typeDesParamètresToString() + ")" + " de la classe existe-t-elle ?";

}

private String typeDesParamètresToString(){

String res = new String("");

for(int i=0; i<this.typeDesParamètres.length;i++){

res = res + this.typeDesParamètres[i].getName();

if(i<this.typeDesParamètres.length-1) res += ", ";

}

return res;

}

public boolean estSatisfaite(Class<?> classe){

try{

classe.getDeclaredMethod(nomDeLaMéthode,typeDesParamètres);

}catch(NoSuchMethodException e){

return false;

}

return true;

}

public boolean equals(Object obj){

if(!(obj instanceof MéthodeExiste)) return false;

MéthodeExiste m = (MéthodeExiste)obj;

return this.nomDeLaMéthode.equals(m.nomDeLaMéthode) &&

java.util.Arrays.equals(this.typeDesParamètres, m.typeDesParamètres);

}

public int hashCode(){

return (nomDeLaMéthode+typeDesParamètresToString()).hashCode();

}

}

(5)

Question2 (6 points) : Une liste de propriétés sur des objets

Nous souhaitons maintenant obtenir la gestion d’une liste de propriétés. La classe ListeDePropriétés<E> se comporte elle-même comme une propriété, elle est satisfaite si toutes les propriétés qui la composent sont satisfaites.

Les classes pour la question1-1 en notation BlueJ/UML :

L’interface ListeDePropriétésI contient les opérations suivantes :

package question2 ;

import question1.PropriétéI;

import java.util.Iterator;

public interface ListeDePropriétésI<E> extends PropriétéI<E>, Iterable<PropriétéI<E>>{

void ajouter(PropriétéI<E> p); // ajout d’une propriété, // pas de doublon possible

void ajouter(ListeDePropriétésI<E> l); // ajout d’une liste de propriétés boolean contient(PropriétéI<E> p); // la propriété est-elle dans la liste ? int taille(); // le nombre de propriétés de cette liste

boolean equals(Object obj); // la méthode equals est demandée int hashCode(); // hashCode est fournie

// issues de l'interface PropriétéI<E>

String toString(); // le cumul des toString de chaque propriété boolean estSatisfaite(E e); // toutes les propriétés sont-elles satisfaites ?

// issue de Iterable<PropriétéI<E>>

Iterator<PropriétéI<E>> iterator(); // parcours de la liste }

Une méthode extraite de la classe de tests unitaires TestListeDePropriétés :

public void test1(){

ListeDePropriétésI<Integer> liste1 = new ListeDePropriétés<Integer>();

liste1.ajouter(new NombreImpair());

liste1.ajouter(new NombreImpair()); // ajout ignoré, propriété déjà présente liste1.ajouter(new NombrePremier());

assertTrue(liste1.taille()==2); // 2 propriétés présentes assertTrue(liste1.contient(new NombreImpair()));

assertTrue(liste1.contient(new NombrePremier()));

assertTrue(liste1.estSatisfaite(3)); // 3 est impair et premier !

(6)

ListeDePropriétésI<Integer> liste2 = new ListeDePropriétés<Integer>();

liste2.ajouter(new NombrePair());

liste2.ajouter(liste1); // liste2 contient 3 propriétés assertFalse(liste2.estSatisfaite(3));

List<PropriétéI<Integer>> liste3 = new ArrayList<PropriétéI<Integer>>();

for(PropriétéI<Integer> p : liste2){ // parcours de liste2 if(p.estSatisfaite(3)) liste3.add(p);

}

// liste3 contient toutes les propriétés satisfaites pour le nombre 3 assertTrue(liste3.size()==2); // impair et premier sont satisfaites assertTrue(liste3.contains(new NombreImpair()));

assertTrue(liste3.contains(new NombrePremier()));

}

Question2-1)

Aux questions 1 et 2, quels patrons auriez-vous choisi pour cette application ? i.e. nous avons des propriétés, des listes de propriétés, des parcours de ces listes, des évaluations …

Patron Composite et (interpréteur ou visiteur)

Question2-2)

Ecrire une implémentation complète de la classe ListeDePropriétés<E>. La méthode equals est demandée, la méthode hashcode est fournie.

import question1.*;

import java.util.Collection;

import java.util.ArrayList;

import java.util.Iterator;

import java.util.List;

import java.lang.reflect.Method;

public class ListeDePropriétés<E> implements ListeDePropriétésI<E>{

private Collection<PropriétéI<E>> propriétés;

public ListeDePropriétés(){

this.propriétés = new ArrayList<PropriétéI<E>>();

}

public void ajouter(PropriétéI<E> p){

if(!contient(p)) propriétés.add(p);

}

public void ajouter(ListeDePropriétésI<E> liste){

for(PropriétéI<E> p : liste){

ajouter(p);

} }

public boolean contient(PropriétéI<E> p){

return propriétés.contains(p);

}

public int taille(){

return propriétés.size();

}

public String toString(){

(7)

return this.propriétés.toString();

}

public boolean estSatisfaite(E e){

for(PropriétéI<E> p : this)

if(!p.estSatisfaite(e)) return false;

return true;

}

public Iterator<PropriétéI<E>> iterator(){

return propriétés.iterator();

}

@Override

public boolean equals(Object obj){

if(!(obj instanceof ListeDePropriétés)) return false;

ListeDePropriétés liste = (ListeDePropriétés)obj;

return this.propriétés.equals(liste.propriétés);

}

@Override

public int hashCode(){

return this.propriétés.hashCode();

} }

Question2-suite )

Afin de vérifier qu’une classe possède bien certaines propriétés, il suffit d’exécuter une suite d’instructions analogue au test suivant :

public void test2(){

ListeDePropriétésI<Class<?>> liste1 = new ListeDePropriétés<Class<?>>();

liste1.ajouter(new NomEnMajuscule());

liste1.ajouter(new MéthodeExiste("ajouterUnitéObtenue",String.class));

liste1.ajouter(new MéthodeExiste("modifier",String.class,String.class));

liste1.ajouter(new MéthodeExiste("unitésObtenues"));

// toutes les propriétés de la liste sont_elle satisfaites ? assertTrue(liste1.estSatisfaite(AuditeurDuCnam.class));

// le test réussi, AuditeurDuCnam contient ces méthodes }

Nous souhaitons engendrer cette suite d’instructions à partir du contenu d’une classe. Nous voulons vérifier que toutes les méthodes d’une classe que nous qualifierons de « modèle » sont présentes dans une classe

quelconque, par exemple si la classe AbstractAuditeur ci-dessous est un « modèle », chaque méthode présente dans cette classe devient une propriété qu’une classe quelconque pourra satisfaire.

Le diagramme des classes en notation BlueJ pour la question 2-3 :

(8)

Une méthode de la classe Utilitaires effectue ce traitement, la méthode obtenirLesPropriétés retourne une liste de propriétés à partir d’une classe « modèle ».

public static ListeDePropriétésI<Class<?>> obtenirLesPropriétés(Class<?> modèle) ;

Si la classe « modèle » AbstractAuditeur contient 3 méthodes :

public abstract class AbstractAuditeur{

public abstract void ajouterUnitéObtenue(String unité);

public abstract List<String> unitésObtenues();

public abstract String toString();

}

Alors cette méthode de la classe de tests réussit :

public void test3(){

ListeDePropriétésI<Class<?>> liste1 = Utilitaires.obtenirLesPropriétés(AbstractAuditeur.class);

// les 3 méthodes de la classe AbstractAuditeur deviennent 3 propriétés de la liste assertTrue(liste1.contient(new MéthodeExiste("ajouterUnitéObtenue",String.class)));

assertTrue(liste1.contient(new MéthodeExiste("toString")));

assertTrue(liste1.contient(new MéthodeExiste("unitésObtenues")));

assertTrue(liste1.taille()==3);

// toutes les propriétés sont satisfaites pour la classe AuditeurDuCnam assertTrue(liste1.estSatisfaite(AuditeurDuCnam.class));

// i.e. la classe AuditeurDuCnam possède au moins toutes les propriétés // du modèle AbstractAuditeur

}

Question2-3)

Ecrire la méthode obtenirLesPropriétés de la classe Utilitaires .

public class Utilitaires{

public static ListeDePropriétésI<Class<?>> obtenirLesPropriétés(Class<?> modèle){

ListeDePropriétésI<Class<?>> liste = new ListeDePropriétés<Class<?>>();

for(Method m : modèle.getDeclaredMethods()){

liste.ajouter(new MéthodeExiste(m.getName(),m.getParameterTypes()));

(9)

}

return liste;

} }

Question3 (6 points) : Sérialisation en XML

Nous souhaitons maintenant disposer d’une sérialisation d’une liste de propriétés en XML, l’API JDOM est utilisée, les arbres XML engendrés respectent la DTD suivante :

<!ELEMENT proprietes (methode_existe*)>

<!ELEMENT methode_existe (parametre*)>

<!ATTLIST methode_existe nom CDATA #REQUIRED>

<!ELEMENT parametre EMPTY>

<!ATTLIST parametre type CDATA #REQUIRED>

Les classes pour cette question en notation BlueJ/UML :

L’interface PropriétésEnXML contient les opérations suivantes :

package question3;

import question2.ListeDePropriétésI;

import org.jdom.Element;

public interface PropriétésEnXML{

/** Une liste de propriétés en arbre XML. */

Element listeEnArbreXML(ListeDePropriétésI<Class<?>> liste);

/** Un arbre XML en liste de propriétés. */

ListeDePropriétésI<Class<?>> arbreXMLEnListe(Element arbreXML);

}

La classe PropriétésEnXMLImpl implémente cette interface. Les quelques lignes suivantes sont extraites de la classe de tests TestSérialisationXML

public void testSimple() throws Exception {

Element racine = new Element("proprietes");

Element methodeAjouterUnitéObtenue = new Element ("methode_existe");

methodeAjouterUnitéObtenue.setAttribute("nom","ajouterUnitéObtenue");

methodeAjouterUnitéObtenue.addContent(new

Element("parametre").setAttribute("type","java.lang.String"));

racine.addContent(methodeAjouterUnitéObtenue);

Element modifier = new Element ("methode_existe");

(10)

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

modifier.addContent(new Element("parametre").setAttribute("type","java.lang.String"));

modifier.addContent(new Element("parametre").setAttribute("type","java.lang.String"));

racine.addContent(modifier);

Element methodeUnitésObtenues = new Element ("methode_existe");

methodeUnitésObtenues.setAttribute("nom","unitésObtenues");

racine.addContent(methodeUnitésObtenues);

PropriétésEnXML props = new PropriétésEnXMLImpl();

ListeDePropriétésI<Class<?>> liste = props.arbreXMLEnListe(racine);

assertTrue(liste.contient(new MéthodeExiste("ajouterUnitéObtenue", String.class)));

assertTrue(liste.contient(new MéthodeExiste("modifier",String.class, String.class)));

assertTrue(liste.contient(new MéthodeExiste("unitésObtenues")));

Document documentXML = new Document( racine,

new DocType("proprietes","proprietes.dtd"));

XMLOutputter out = new XMLOutputter(Format.getPrettyFormat());

out.output(documentXML,System.out);

}

Ci-dessous le document xml affiché sur la console, à la suite de l’exécution de cette méthode de test :

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE proprietes SYSTEM "proprietes.dtd">

<proprietes>

<methode_existe nom="ajouterUnitéObtenue">

<parametre type="java.lang.String" />

</methode_existe>

<methode_existe nom="modifier">

<parametre type="java.lang.String" />

<parametre type="java.lang.String" />

</methode_existe>

<methode_existe nom="unitésObtenues" />

</proprietes>

Une autre méthode extraite de la classe de tests TestSérialisationXML

public void testEcritureEtLecture() throws Exception {

// obtention de la liste des propriétés liste1 à partir d’une classe ListeDePropriétésI<Class<?>> liste1 ;

liste1 = Utilitaires.obtenirLesPropriétés(java.util.ArrayList.class);

PropriétésEnXML props = new PropriétésEnXMLImpl();

// Obtention d’un arbre XML à partir de la liste1 Element arbre = props.listeEnArbreXML(liste1);

// Obtention d’une liste de propriétés à partir de cet arbre XML arbre ListeDePropriétésI<Class<?>> liste = props.arbreXMLEnListe(arbre);

// les deux listes obtenues liste et liste1 doivent être égales assertTrue(liste.equals(liste1));

}

(11)

Question3)

Ecrire une implémentation complète de la classe PropriétésEnXMLImpl.

package question3;

import question1.*;

import question2.*;

import question3.*;

import org.jdom.*;

import java.util.*;

public class PropriétésEnXMLImpl implements PropriétésEnXML{

public Element listeEnArbreXML(ListeDePropriétésI<Class<?>> liste){

Element racine = new Element("proprietes");

for(PropriétéI<Class<?>> p : liste){

if(p instanceof MéthodeExiste){

MéthodeExiste m = (MéthodeExiste) p;

Element elt = new

Element("methode_existe").setAttribute("nom",m.nom());

for(Class<?> t : m.typeDesParamètres()){

elt.addContent(new

Element("parametre").setAttribute("type",t.getName()));

}

racine.addContent(elt);

} }

return racine;

}

public ListeDePropriétésI<Class<?>> arbreXMLEnListe(Element arbreXML){

ListeDePropriétésI<Class<?>> liste = new ListeDePropriétés<Class<?>>();

List children = arbreXML.getChildren();

for (Object o : children) { Element el = (Element)o;

List listeClasse = el.getChildren();

Class<?>[] classArray = new Class<?>[listeClasse.size()];

for (int i = 0; i<listeClasse.size(); i++) { Element classe = (Element)listeClasse.get(i);

try {

String type = classe.getAttributeValue("type");

if(primitif.get(type) != null) // c'est un type primitif classArray[i] = primitif.get(type);

else

classArray[i] = Class.forName(type);

} catch(Exception e) {

throw new RuntimeException(e);

} }

PropriétéI<Class<?>> prop = new

MéthodeExiste(el.getAttributeValue("nom"), classArray);

liste.ajouter(prop);

}

return liste;

}

private static Map<String,Class<?>> primitif;

static{

primitif = new HashMap<String,Class<?>>();

primitif.put("int",Integer.TYPE);

(12)

primitif.put("long",Long.TYPE);

primitif.put("short",Short.TYPE);

primitif.put("byte",Byte.TYPE);

primitif.put("char",Character.TYPE);

primitif.put("double",Double.TYPE);

primitif.put("float",Float.TYPE);

} }

Question4 (4 points) : Interface graphique

Nous définissons maintenant une interface graphique en Swing qui permet de vérifier qu’une classe possède bien les propriétés issues d’un modèle.

Exemple 1) Le modèle est la classe AbstractAuditeur, la classe testée est la classe AuditeurDuCnam

L’appui sur le bouton « vérifier » engendre cette fenêtre de résultats

Exemple 2) Le modèle est la classe java.util.AbstractList, la classe testée est la classe java.util.ArrayList

(13)

L’appui sur le bouton « vérifier » engendre cette fenêtre de résultats

Ci-dessous, la classe correspondant à cette interface graphique

public class VérificateurSwing extends JFrame {

private JTextField nomClasse = new JTextField("question2.AuditeurDuCnam", 20);

private JTextField modeleClasse = new JTextField("question2.AbstractAuditeur", 20);

private JButton bVerifier = new JButton("vérifier");

//private JButton bQuitter = new JButton("Quitter");

private JTextArea resultats = new JTextArea(10, 40);

public VérificateurSwing() { super("Vérificateur");

JTabbedPane onglets = new JTabbedPane();

this.getContentPane().add(onglets);

JPanel parametres = new JPanel(new BorderLayout());

onglets.addTab("paramètres", parametres);

// Construire la partie supérieure

JPanel saisies = new JPanel(new GridLayout(2, 2));

saisies.add(new JLabel("Classe à vérifier : "));

saisies.add(nomClasse);

saisies.add(new JLabel("Modèle de classe : "));

saisies.add(modeleClasse);

parametres.add(saisies, BorderLayout.NORTH);

// Construire les boutons de commandes inférieurs JPanel boutons = new JPanel();

boutons.setLayout(new FlowLayout());

boutons.add(bVerifier);

//boutons.add(bQuitter);

parametres.add(boutons, BorderLayout.SOUTH);

// Construire l’onglet résultat

(14)

onglets.addTab("résultats", new JScrollPane(resultats));

bVerifier.addActionListener( /* à completer */); // à recopier sur votre copie

this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

this.pack();

this.setVisible(true);

}

public static void main(String[] args) { new VérificateurSwing();

} }

Question4)

Complétez cette application afin que le bouton « vérifier » soit actif. La méthode setText(String) permet d’afficher un texte dans un onglet, par exemple, pour l’onglet résultats : resultats.setText("les Propriétés :

\n");

bVerifier.addActionListener(new ActionVerifier());

private class ActionVerifier implements ActionListener{

public void actionPerformed(ActionEvent ae){

try{

Class<?> modèle = Class.forName(modeleClasse.getText());

Class<?> laClasse = Class.forName(nomClasse.getText());

ListeDePropriétésI<Class<?>> liste1 = Utilitaires.obtenirLesPropriétés(modèle);

String res = "";

for(PropriétéI<Class<?>> p : liste1){

if(p.estSatisfaite(laClasse)){

res += p.toString() + " : oui.\n";

}else{

res += p.toString() + " : non.\n";

} }

resultats.setText("les Propriétés : \n" + res);

}catch(Exception e){

resultats.setText("exception : \n" + e.toString());

} } }

Références

Documents relatifs

[r]

■ Un mur végétal est souvent associé à des plantes dépolluantes : on choisit des plantes tropicales comme le lierre, l’aglaonema, la fougère ou le philodendron ou d'autres plantes

Recopier et compléter sur la copie la fonction Python ci-dessous pour qu’elle détermine le nombre minimum d’années nécessaires afin que le prix du téléphone dépasse 1000

On admet que le processus d’élimination du médicament peut être modélisé par une

S’il est choisi par l’équipe pédagogique, il est nécessaire que chaque élève dispose d’une impression en couleur.. ☐ Ce sujet contient des pièces jointes de type audio

−2 ) est un vecteur directeur de la

Des contrôles de qualité montrent que 10 % des boîtes provenant du fournisseur « Au thé de qualité » présentent des traces de pesticides et que 20 % de celles provenant

Sachant que Jules a choisi un chaton couleur Blue dans cette animalerie, quelle est la probabilité que le chaton provienne du deuxième élevage. On donnera le résultat à 10 −2