IFT232_Exercices_Factory_sol

publicité
IFT 232 Méthodes de conception orientée objets
Séance d’exercices IV
Date : 31 janvier et 7 février 2005
Objectifs
 Comprendre et maîtriser le design pattern « Factory Method »
 Comprendre et maîtriser le design pattern « Abstract Factory»
Factory method design pattern
Enoncé :
Tout programme doit pouvoir rapporter les erreurs ou encore afficher des messages
servant pour le déverminage. Soit l’interface suivante
public interface Trace {
// turn on and off debugging
public void setDebug( boolean debug );
// write out a debug message
public void debug( String message );
// write out an error message
public void error( String message );
}
Question 1 :
Écrire une classe SystemTrace qui implémente Trace. Les instances de cette classe
affiche le résultat dans la fenêtre de commande en ligne.
public class SystemTrace implements Trace {
private boolean debug;
public void setDebug( boolean debug ) {
this.debug = debug;
}
public void debug( String message ) {
if( debug ) { // only print if debug is true
System.out.println( "DEBUG: " + message );
}
}
public void error( String message ) {
// always print out errors
System.out.println( "ERROR: " + message );
}
}
Question 2 :
Ajouter les instructions de déverminage nécessaires pour tracer sur la console chacun des
appels de méthodes de votre solution de la séance d’exercices III.
Dans la classe, il faut ajouter les instructions suivantes :
//... some code ...
SystemTrace log = new SystemTrace();
//... code ...
log.debug( "entering loog" );
// ... etc ...
Par contre dès que l’on voudra changer d’implémentation (par exemple, utiliser celle de
la Q3), il faudra modifier cette classe.
Question 3 :
Écrire une classe FileTrace qui implémente Trace. Les instances de cette classe
affiche le résultat dans un fichier.
public class FileTrace implements Trace {
private java.io.PrintWriter pw;
private boolean debug;
public FileTrace() throws java.io.IOException {
// a real FileTrace would need to obtain the filename
somewhere
// for the example I'll hardcode it
pw = new java.io.PrintWriter( new java.io.FileWriter(
"c:\trace.log" ) );
}
public void setDebug( boolean debug ) {
this.debug = debug;
}
public void debug( String message ) {
if( debug ) { // only print if debug is true
pw.println( "DEBUG: " + message );
pw.flush();
}
}
public void error( String message ) {
// always print out errors
pw.println( "ERROR: " + message );
pw.flush();
}
}
Question 4 :
Modifier votre réponse à la question 2 pour conserver la trace dans un fichier. Le nom de
ce fichier sera spécifié dans les propriétés du programme et chargé dans une instance de
ProgramProperties. Cette instance sera un Singleton créé à sa première utilisation.
Cette classe sera sous-classe de java.util.Properties.
Si vous n’êtes pas familier avec les alternatives permettant de déterminer les propriétés
d’un programme, voir
http://java.sun.com/docs/books/tutorial/essential/attributes/index.html
public class ProgramProperties extends Properties {
final static public String DEFAULT_FILE_NAME = "defaultProperties";
final static public String PROPS_FILE_NAME = "ex4.properties";
static private ProgramProperties instance__;
static synchronized public ProgramProperties getInstance() {
if (instance__ == null) {
// create and load default properties
ProgramProperties defaultProps = new ProgramProperties();
FileInputStream in;
try {
in = new FileInputStream(DEFAULT_FILE_NAME);
defaultProps.load(in);
in.close();
} catch (FileNotFoundException e2) {
e2.printStackTrace();
}
catch (IOException e3) {
e3.printStackTrace();
}
// create program properties with default
ProgramProperties applicationProps = new
ProgramProperties(defaultProps);
try {
// now load properties from last invocation
in = new FileInputStream(PROPS_FILE_NAME);
applicationProps.load(in);
try {
in.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
}
} catch (IOException e1) {
e1.printStackTrace();
}
instance__ = applicationProps;}
return instance__;
}
private ProgramProperties(ProgramProperties defaultProps){
super(defaultProps);
}
private ProgramProperties() {
super();
}
}
Question 5 :
Vous avez probablement dû modifier votre programme en plusieurs endroits dans
plusieurs classes. Afin de rassembler la création du système de trace en un seul endroit,
écrivez une classe TraceFactory possédant une méthode « factory » abstraite
getTrace().
Voir plus loin pour le code de la classe TraceFactory
Question 6 :
Ecrivez la classe SystemTraceFactory qui est une sous-classe de TraceFactory.
Cette classe rend une instance de la classe SystemTrace.
public class SystemTraceFactory extends TraceFactory {
public Trace getTrace() {
return new SystemTrace();
}
}
Question 7 :
Ecrivez la classe FileTraceFactory qui est une sous-classe de TraceFactory
Cette classe rend une instance de la classe FileTrace.
import java.io.IOException;
public class FileTraceFactory extends TraceFactory {
public Trace getTrace() {
try {
return new FileTrace();
} catch (IOException e) {
e.printStackTrace();
}
// pour au mons render de quoi faire la trace
return new SystemTrace();
}
}
Question 8 :
Transformez TraceFactory en Singleton. La classe de l’instance sera spécifée dans le
fichier de propriétés du programme. Par défaut, une instance de la classe
SystemTraceFactory.
public abstract class TraceFactory {
static private TraceFactory instance__;
private static TraceFactory createFactory() {
if (ProgramProperties.getInstance().getProperty("trace.file") != null)
return new FileTraceFactory();
return new SystemTraceFactory();
}
static synchronized public TraceFactory getInstance() {
if (instance__ == null)
instance__ = createFactory();
return instance__;
}
public abstract Trace getTrace();
}
Remarques
http://java.sun.com/j2se/1.4.2/docs/guide/util/logging/
http://www.javaworld.com/javaworld/javaqa/2001-05/02-qa-0511-factory.html?
Abstract Factory design pattern
Enoncé :
Vos clients sont américains et français. Bien entendu, les américains tiennent mordicus à
travailler avec des mesures en système impérial alors que les français tiennent
absolument au système métrique.
Implémentez à l’aide du patron de conception « Abstract Factory» un programme qui
garantisse aux utilisateurs de ne travailler que dans un seul des deux systèmes de mesure.
Le système de mesure sera spécifié dans un fichier de propriétés.
public class MeasureFactory {
//un meilleur design serait celui défini aux questions précéentes
public Measure getVolume(Number n, String u)
{
if
(ProgramProperties.getInstance().getProperty("measure.system") == "us")
return new MeasureUSImpl(n, u);
return new MeasureMetricImpl(n,u);
}
public String getVolumeDefaultUnit(){return null;}
public Measure getWeight(Number n, String u){return null;}
public String getWeightDefaultUnit(){return null;}
}
public interface Measure {
String getUnits();
Number getValue();
Measure add(Measure qty);
Measure substract(Measure qty);
}
public interface MeasureMetric extends Measure {
public static String MILLILITRES = "ml";
public static String LITRES = "l";
public static String MILLIGRAMMES = "mg";
public static String GRAMMES = "g";
}
public class MeasureMetricImpl implements MeasureMetric {
/**
* @param n
* @param u
*/
public MeasureMetricImpl(Number n, String u) {
// TODO Auto-generated constructor stub
}
public String getUnits() {
// TODO Auto-generated method stub
return null;
}
public Number getValue() {
// TODO Auto-generated method stub
return null;
}
public Measure add(Measure qty) {
// TODO Auto-generated method stub
return null;
}
public Measure substract(Measure qty) {
// TODO Auto-generated method stub
return null;
}
}
Téléchargement