diff --git a/README.md b/README.md index 478ddfd..a42eab2 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,4 @@ +[![Review Assignment Due Date](https://classroom.github.com/assets/deadline-readme-button-24ddc0f5d75046c5622901739e7c5dd533143b0c8e959d652212380cedb1ea36.svg)](https://classroom.github.com/a/iqalO_EZ) # Simulation de Vélo Dans ce TP, vous réalisez des exercices sur les **patrons de conception**[^1] à l'aide d'une application simple qui simule, d'une manière très approximative, le fonctionnement d'un vélo. diff --git a/Rapport.md b/Rapport.md index bcaa28f..4e8b130 100644 --- a/Rapport.md +++ b/Rapport.md @@ -1,21 +1,70 @@ # Compte Rendu du TP 1 : Patrons de Conceptions -Noms des étudiants du binôme : +Noms des étudiants du binôme : MINTCHUENG KARELLE ## Exercices 1 +Le modèle reflète le Patron de conception *Composite* le 'MobileObject' agit en tant que Composant, qui définit une interface pour les objets dans la composition +le 'Vehicle' joue le rôle de composite car elle stocke des composants enfants (instances de 'MobileObject') et implémente l'interface 'MobileObject'. + +La méthode 'getVelocity()' n'as plus besion d'être écrite à nouveau car la classe 'Vehicle' fournit déjà une implémentation qui calcule la vitesse comme +une moyenne pondérée des vitesses de ses composants, ce qui est le comportement désiré pour 'TagAlongBike' +La methode 'getMasse()' n'a pas non plus besoin d'être écrite car l'implémentation heritée de 'Vehicle' calcule déjà la masse en sommant les masses de tous les composants. + ## Exercices 2 +Le Patron de conception utilisé par la méthode 'getVelocity()' de la classe 'Vehicle' est le patron de conception itérateur pour parcourir les composants d'un véhicule , un +itérateur est une interface qui permet de parcourir une collection élement par élement, sans exposer les details de la collection sous-jacente. + +Avantage du patron itérateur : *Abstraction* : l'itérateur cache la complexité de parcours de la structure de données sous-jacente. ce qui permet d'utiliser le même code pour +parcourir différents types de collections sans se soucier de leur implémentation interne. +*Découplage* : Il découple les algorithmes des structures de données sur lesquelles ils opèrent ce qui améliore la maintenance et la réutilisation du code. +*Contrôle* : il fournit un contrôle sur le processus de parcours, ce qui peut être utilisé pour les opérations spécifiques comme l'insertion ou la suppression pendant l'itération + +La modification de 'Set' à 'List' n'implique pas nécessairement une modification de la méthode 'getVelocity()' parce que les deux implémentations fournissent un itérateur via la méthode 'iterator()' utilisée dans la méthode actuelle. Cependant il est à noté que +la 'List' maintient l'ordre des élements, tandis que 'Set' ne le fait pas + ## Exercices 3 +Les étapes de la creation du singleton Clock sont les suivantes : +-Modifier le constructeur de la classe 'Clock' pour le rendre privé ce qui empêche l'instanciation directe de la classe depuis l'extérieur et assure que la classe ne peut être instanciée qu'à l'intérieur de celle-ci +-Ajouter une propriété privée dans la classe 'Clock' pour stocker l'unique instance de la classe. Cette instance est généralement initialisée directement lors de la déclaration ou plus tardivement dans la méthode statique 'getInstance()' +-Créer une méthode publique statique 'getInstance' qui retourne l'unique instance de la classe +-Remplacer toutes les instanciations directes de la classe 'Clock' par des appels à 'Clock.getInstance' ce qui va nous permettre de garantir que tous les composants utilisent la même instance pour l'horloge ce qui va permettre une synchronisation à travers toute l'application. + ## Exercices 4 +- Non 'Bike' et 'Wheel' n'appartiennent pas au même paquetage car 'bike' appartient au paquage Cycling et 'Wheel ' appartient au paquage transport +- La classe 'Wheel' depend de la classe 'Bike' pour obtenir la force de poussée via la méthode 'getPush()' il s'agit d'une méthode directe et bidirectionnelle car 'Bike' a des références à ses roues +et 'Wheel' à une référence à 'Bike' il s'agit d'une mauvaise pratique car il s'agit d'une dépendance cyclique entre 'Bike' et 'Wheel' +ce qui crée un couplage fort entre les deux classes du fait que, un changement dans l'une peut affecter directement l'autre, ce qui rend le système fragile et difficile à évoluer +- 'Bike' est utilisée par 'Wheel' pour calculer la vitesse de la roue via la méthode 'getPush' +- Oui, il existe déjà une abstraction de la classe 'Bike' qui est la classe 'Vehicle'(puisque 'Bike' etend 'Vehicle'). la méthode 'hetPush()' utilisée par 'Wheel' n'est pas astraite dans 'Vehicle', mais +pourrait être ajoutée en tant que méthode abstraite à 'Vehicle' ou en tant qu'interface séparée +- L'abstraction 'Vehicle' se trouve dans le paquetage transport +- Pour casser la dépendance cyclique, on pourrait introduire une interface, par exemple 'PushProvider', qui aurait une méthode 'getPush()'.'Bike' implémenterait cette interface ensuite, 'Wheel' ne dépendrait plus de 'Bike' directement, mais plutôt de l'interface 'PushProvider' + + ## Exercices 5 + ## Exercices 6 +La différence entre la méthode de fabrique (Factory method) et le singleton est le suivant : +- Singleton : assurequ'une classe n'a qu'une seule instance et fournit un point d'accès global à cette instance ce qui est utile pour les ressources qui doivent être partagées, comme +une horloge +- La méthode fabriqueb: permet de creer des objets sans spécifier la classe exacte de l'objet qui ser crée ce qui permet de centraliser la logique de création des instances, offrant ainsi plus de flexibilité pour changer le type d'objets +crées sans changer le code qui utilise ces objets. + ## Exercices 7 ## Exercices 8 +-Le Patron de conception de la classe context avec ServiceLoader suit le patron de conception FACADE car en encapsulant la complexité de 'ServiceLoader' derrière une interface simplifiée, 'context' rend l'utilisation des services plus accessible et plus +simple pour les utilisateurs. Ce qui va permettre de centraliser la création et la gestion des instances, facilitant ainsi la maintenance et l'évolution de l'application. +-Oui nous pouvons avoir plusieurs lignes dans le fichier de services "fr.polytech.sim.cycling.Bike". Chaque ligne dans ce fichier va correspondre à une implémentation différente du type de service spécifié.'ServiceLoader' les utilisera pour charger toutes les implémentationsdisponibles du service +l'utilisation de 'injectAll' va permettre d'itéree sur toutes les instances disponibles pour le type de service demandé +## Exercices 9 +-La méthode "injectAll()" de la classe 'context' retourne un 'Iterator', ce qui correspondant au patron de conception Iterateur. Ce patron permet d'accéder séquentiellement aux élements d'une collection sans exposer ses représentations sous-jacentes. +Elle va fournir une façon standard de parcourir des collectionsnet est utilisé dans la bibliothèque standard java pour parcourir tout objet implémentant l'interface 'Iterable' diff --git a/src/main/java/fr/polytech/sim/Clock.java b/src/main/java/fr/polytech/sim/Clock.java index 29c34b1..75f7c26 100644 --- a/src/main/java/fr/polytech/sim/Clock.java +++ b/src/main/java/fr/polytech/sim/Clock.java @@ -6,8 +6,24 @@ * A clock used to synchronize simulations. */ public class Clock { - private final int time = new Random().nextInt(25); + private static final Clock instance = new Clock(); + + private final int time; + + // Constructeur privé + private Clock(){ + this.time = new Random().nextInt(25); + } + + /** + * Acces à l'instance unique de l'horloge + * @return l'instance singleton de clock + */ + + public static Clock getInstance(){ + return instance; + } /** * Random integer between 0 and 24 inclusive. */ diff --git a/src/main/java/fr/polytech/sim/cycling/Bike.java b/src/main/java/fr/polytech/sim/cycling/Bike.java index d44a725..d7c0713 100644 --- a/src/main/java/fr/polytech/sim/cycling/Bike.java +++ b/src/main/java/fr/polytech/sim/cycling/Bike.java @@ -1,11 +1,12 @@ package fr.polytech.sim.cycling; import fr.polytech.sim.transport.Vehicle; +import fr.polytech.sim.transport.PushProvider; /** * Abstract bike. */ -public abstract class Bike extends Vehicle { +public abstract class Bike extends Vehicle implements PushProvider { @Override public double getPush() { diff --git a/src/main/java/fr/polytech/sim/cycling/BikeSimulator.java b/src/main/java/fr/polytech/sim/cycling/BikeSimulator.java index ab371ca..852cfea 100644 --- a/src/main/java/fr/polytech/sim/cycling/BikeSimulator.java +++ b/src/main/java/fr/polytech/sim/cycling/BikeSimulator.java @@ -3,16 +3,27 @@ import fr.polytech.sim.Simulation; import fr.polytech.sim.log.FileLogger; import fr.polytech.sim.log.Logger; +import fr.polytech.sim.log.LoggerFactory; +import fr.polytech.sim.utils.Context; + +import java.util.Iterator; /** * Bike simulation. */ -public class BikeSimulator implements Simulation { - private final Logger logger = new FileLogger("BikeSimulator"); + public class BikeSimulator implements Simulation { + private final Logger logger = LoggerFactory.getLogger("NomDuLogger"); public void run() { - Bike bike = new SimpleBike(); - this.logger.log("Bike's speed %.2f Km/h.", bike.getVelocity()); - this.logger.log("Bike's mass %.2f Kg.", bike.getMass()); + // On utilise Context.injectAll pour obtenir toutes les instances de Bike + Iterator bikes = Context.injectAll(Bike.class); + while (bikes.hasNext()) { + Bike bike = bikes.next(); + // Log les information pour chaque Bike + logger.log("Simulating bike: %s ", bike.getClass().getSimpleName()); + logger.log("Bike's speed : %.2f km/h.", bike.getVelocity()); + logger.log("Bike's mass : %.2f kg.", bike.getMass()); + } + } -} +} \ No newline at end of file diff --git a/src/main/java/fr/polytech/sim/cycling/TagAlongBike.java b/src/main/java/fr/polytech/sim/cycling/TagAlongBike.java new file mode 100644 index 0000000..386ff4a --- /dev/null +++ b/src/main/java/fr/polytech/sim/cycling/TagAlongBike.java @@ -0,0 +1,28 @@ +package fr.polytech.sim.cycling; + +import fr.polytech.sim.transport.Vehicle; +import fr.polytech.sim.transport.Wheel; + +public class TagAlongBike extends Bike { + + private Bike parentBike; + private Bike childBike; + private Wheel frontWheel; + private Wheel backWheel ; + public TagAlongBike(Bike parentBike, Bike childBike) { + super(); + this.parentBike = parentBike; + this.childBike = childBike; + + this.frontWheel = new Wheel(this); + this.backWheel = new Wheel(this); + this.components.add(parentBike); + this.components.add(childBike); + this.components.add(frontWheel); + this.components.add(backWheel); + } + @Override + public double getPush(){ + return parentBike.getPush(); + } +} diff --git a/src/main/java/fr/polytech/sim/log/ConsoleLogger.java b/src/main/java/fr/polytech/sim/log/ConsoleLogger.java index a60427e..74fdc71 100644 --- a/src/main/java/fr/polytech/sim/log/ConsoleLogger.java +++ b/src/main/java/fr/polytech/sim/log/ConsoleLogger.java @@ -16,8 +16,8 @@ public ConsoleLogger(String name) { @Override public void log(String format, Object... args) { - String entry = String.format(format, args); - String message = String.format("%s\t%s\n", this.name, entry); - System.out.print(message); + + String message = logMessage(format, args);// construction du message ne utilisant la methode de la classe de base + System.out.print(message);// affichage du message au niveau de la console } } diff --git a/src/main/java/fr/polytech/sim/log/FileLogger.java b/src/main/java/fr/polytech/sim/log/FileLogger.java index 1a6788d..ed59f37 100644 --- a/src/main/java/fr/polytech/sim/log/FileLogger.java +++ b/src/main/java/fr/polytech/sim/log/FileLogger.java @@ -20,10 +20,9 @@ public FileLogger(String name) { @Override synchronized public void log(String format, Object... args) { - String entry = String.format(format, args); - String message = String.format("%s\t%s\n", this.name, entry); + String message = logMessage(format,args);// Construction du message en utilisant la méthode de la classe de base try (FileWriter fileWriter = new FileWriter(FILE_NAME, true)) { - fileWriter.write(message); + fileWriter.write(message); // ecrire le message dans le fichier de logs } catch (IOException e) { throw new RuntimeException(e); } diff --git a/src/main/java/fr/polytech/sim/log/NamedLogger.java b/src/main/java/fr/polytech/sim/log/NamedLogger.java index 64c57a2..6022dbe 100644 --- a/src/main/java/fr/polytech/sim/log/NamedLogger.java +++ b/src/main/java/fr/polytech/sim/log/NamedLogger.java @@ -16,4 +16,10 @@ protected NamedLogger(String name) { this.name = name; } + protected String logMessage(String format, Object...args){ + //Méthode modèle pour construire le message de log + String entry = String.format(format, args); + return String.format("%s\t%s\n" , this.name, entry); + } + } diff --git a/src/main/java/fr/polytech/sim/transport/PushProvider.java b/src/main/java/fr/polytech/sim/transport/PushProvider.java new file mode 100644 index 0000000..3314244 --- /dev/null +++ b/src/main/java/fr/polytech/sim/transport/PushProvider.java @@ -0,0 +1,5 @@ +package fr.polytech.sim.transport; + +public interface PushProvider { + double getPush(); +} diff --git a/src/main/java/fr/polytech/sim/transport/Vehicle.java b/src/main/java/fr/polytech/sim/transport/Vehicle.java index f87723f..4768589 100644 --- a/src/main/java/fr/polytech/sim/transport/Vehicle.java +++ b/src/main/java/fr/polytech/sim/transport/Vehicle.java @@ -2,18 +2,18 @@ import fr.polytech.sim.log.ConsoleLogger; import fr.polytech.sim.log.Logger; -import java.util.HashSet; -import java.util.Iterator; -import java.util.Set; +import fr.polytech.sim.log.LoggerFactory; + +import java.util.*; /** * Vehicle abstraction. */ public abstract class Vehicle implements MobileObject { - private final Logger logger = new ConsoleLogger("Vehicle"); - protected final Set components = new HashSet<>(); + protected final List components = new ArrayList<>(); + private final Logger logger = LoggerFactory.getLogger("NomDuLogger"); /** * Force applied to push the vehicle. * diff --git a/src/main/java/fr/polytech/sim/transport/Wheel.java b/src/main/java/fr/polytech/sim/transport/Wheel.java index 63ca7b7..9840ead 100644 --- a/src/main/java/fr/polytech/sim/transport/Wheel.java +++ b/src/main/java/fr/polytech/sim/transport/Wheel.java @@ -4,6 +4,8 @@ import fr.polytech.sim.cycling.Bike; import fr.polytech.sim.log.ConsoleLogger; import fr.polytech.sim.log.Logger; +import fr.polytech.sim.log.LoggerFactory; + import java.util.Objects; /** @@ -12,16 +14,18 @@ public class Wheel implements MobileObject { private static final double DEFAULT_MASSE = 10; - private final Logger logger = new ConsoleLogger("Wheel"); - private final Clock clock = new Clock(); - private final Bike drive; + private final Clock clock = Clock.getInstance();// permet de récuperer l'instance lors de la creation du singleton + private final PushProvider drive; + private final Logger logger = LoggerFactory.getLogger("NomDuLogger"); + + /** * Constructor. * * @param drive the object providing push power. */ - public Wheel(Bike drive) { + public Wheel(PushProvider drive) { Objects.requireNonNull(drive, "Bike must not be null."); this.drive = drive; } diff --git a/src/main/java/fr/polytech/sim/utils/Context.java b/src/main/java/fr/polytech/sim/utils/Context.java index 61461f8..9d7c458 100644 --- a/src/main/java/fr/polytech/sim/utils/Context.java +++ b/src/main/java/fr/polytech/sim/utils/Context.java @@ -36,6 +36,8 @@ public static T inject(Class klass) { */ public static Iterator injectAll(Class klass) { /* TODO: implement the right logic */ - throw new UnsupportedOperationException("Method not implemented"); + ServiceLoader loader = ServiceLoader.load(klass); + return loader.iterator(); + //throw new UnsupportedOperationException("Method not implemented"); } } diff --git a/src/main/resources/META-INF/services/fr.polytech.sim.cycling.Bike b/src/main/resources/META-INF/services/fr.polytech.sim.cycling.Bike index 3a9e731..e36a93d 100644 --- a/src/main/resources/META-INF/services/fr.polytech.sim.cycling.Bike +++ b/src/main/resources/META-INF/services/fr.polytech.sim.cycling.Bike @@ -1 +1,2 @@ fr.polytech.sim.cycling.SimpleBike +fr.polytech.sim.cycling.TagAlongBike