====== Applications des principes SOLID ====== Essayez de ne pas tricher, répondez aux questions une par une. Attention, l'exercice peut vous paraitre très facile au départ, mais vous avez vraiment intérêt à maintenir un modèle de classe cohérent à côté pour faire cet exercice. Certains aspects font penser aux bases de données. Nous verrons plus tard cet aspect. Pour l'instant, réfléchissez uniquement "Objet". ===== Modèles de Voiture (10mn) ===== On distingue deux formes de consommation pour un même modèle de voiture : * la consommation moyenne sur route, urbaine ou mixte [[http://www.fiches-auto.fr/articles-auto/chiffres-consommation/peugeot.php|exemples]] en litres aux 100km * la consommation en fonction de la vitesse qui suit la règle suivante ((extraite d'un [[http://www.ilemaths.net/forum-sujet-219647.html|forum de mathématiques]])), elle ne prétend pas être vraie C(v) = 2(d/v) + K v^2 avec v en km/heures, d en km et k un coefficient variable en fonction des voitures. Si une voiture roule à ''150 km/h'' sa consommation est donc en ''litres aux 100km'' de : C(150) = 2(100/150) + K * 150^2 pour la Cl Avec un coefficient de ''3,85*10^-4'', ''C(150) = 9.99583333333; C(64) = 4,7 litres au 100km'' Ce qui en java peut se coder par une ligne comme : double consommation = 2*(100/vitesse) + coeff*vitesse*vitesse; -Quelle modélisation proposez-vous pour supporter les opérations suivantes : - Je veux pouvoir déclarer que le modèle Clio a une consommation moyenne sur Route de 6,3, urbaine de 8,1, .... - Je veux pouvoir déclarer que le modèle Clio a un coefficient "k" de 3,85*10^-4 - Je veux pouvoir demander la consommation moyenne du modèle Clio sur Route (rep. 6,3)? urbaine(rep. 8,1)? - Je veux pouvoir demander la consommation moyenne d'une Clio à 150km/h? (mettons que le coefficient est de 3,85*10^-4 et donc obtenir une réponse de quasi 10, ... ce qui n'est pas vraiment la réalité!!! ). - Réfléchissez à l'implémentation et proposer un modèle de classe qui répond à ces fonctionnalités, puis implémentez le. - On intègre à présent la consommation "Mixte", qu'est-ce qui change dans votre modèle? dans votre code? ===== Calcul du CO2 (20mn max) ===== On définit un **calculateur d'émission de CO2** qui respecte les règles suivantes (voir http://www.ecoscore.be/fr/comment-calculer-les-%C3%A9missions-de-co2-en-fonction-de-la-quantit%C3%A9-de-carburant-consomm%C3%A9) **Pour un moteur Diesel :** 1 litre de diesel pèse 835 grammes. Le diesel est composé à 86.2% de carbone (C), ce qui correspond à 720 g de C par litre de diesel. Pour brûler ce C en CO2, 1920 g d’oxygène sont nécessaires. La somme nous donne donc 720 + 1920 = 2640 g de CO2 par litre de diesel. Une voiture qui consomme 5 litre/100km va donc émettre 5L x 2640 g/L / 100 (par km) = 132 g CO2/km. **Pour un moteur Essence :** 1 litre d’essence pèse 750 grammes. L’essence est composée à 87% de carbone (C), ce qui correspond à 652 g de C par litre d’essence. Pour brûler ce C en CO2, 1740 g d’oxygène sont nécessaires. La somme nous donne donc 652 + 1740 = 2392 g de CO2 par litre d’essence. Une voiture qui consomme 5 litre/100km va donc émettre 5L x 2392 g/L / 100 (par km) = 120 g CO2/km. - Créer une classe calculateur de CO2 selon les règles précédentes telle que : - A la création d'une instance du calculateur, on donne le type de carburant, ce qui a pour conséquence d'associer au calculateur le bon coefficient de calcul : - la méthode de calcul de l'émission est donc ''emissionCO2(ConsommationLitreAuCent) : g CO2/km'' - Etendre le modèle de voiture et le code réalisé précédemment pour pouvoir obtenir la production de CO2 d'un modèle de voiture **selon les types de route**. - Attention tous les tests réalisés précédemment doivent rester valides. - Pensez vous que votre modèle/code respecte le principe Ouvert-Fermé? ===== Extensions et Indépendance des classes (20mn) ===== - Avec le système ADBLUE la production de CO2 des diesels est réduite de 85%. Définir un nouveau Calculateur qui tient compte de du ADBLUE dans le calcul de l'émission de CO2 pour les diesels. Il a exactement la même interface que le calculateur précédent. - Les modèles de voitures équipés du système "ADBLUE" utilisent ce calculateur. Quelle solution proposez-vous? Il y a plusieurs solutions. - Quel coût en terme de modification des codes a eu cette extension? - Pour certains véhicules professionnels un calculateur est fourni en ligne (cf. http://www.total.fr/pro/carburants/gazoles/calculateur-co2.html). Définir un calculateur qui renvoie toutes les demandes vers un tel calculateur. Vous simulerez cet appel en renvoyant toujours la même valeur. Un tel "proxy" pourrait dans la réalité extrapoler les modèles en fonction de la consommation du véhicule. - Nous décidons de créer une catégorie de modèles de véhicules professionnels qui font par défaut référence à ce calculateur et intègrent en plus une charge possible. Un Berlingot sera un tel exemple. Il n'existe pas UNE solution mais vous devez pouvoir justifier VOTRE solution. ===== Séparation des Interfaces (15 mn) ===== On définit un analyseur de flottes de voitures qui parcourent toutes les modèles de voitures de la flotte et récupère pour chacun ses émissions de CO2 sur route et en fait la moyenne. - Comment modifiez vous votre Modèle de voiture pour respecter le principe de séparation des interfaces? ===== Couplage et indépendance (10 mn) ===== Tous les modèles de voiture n'ont pas la même manière de faire les calculs mais à la fin on veut tous les interroger de la même manière ! On vient d'établir une formule ((C'est possible, mais je ne l'ai pas trouvé...)) qui, **pour certains modèles de voitures**, à partir des données connues en circulation urbaine ou sur route permet de déterminer le coefficient K, selon la formule suivante : On calcule le coefficient en multipliant par 10^-4, la consommation sur route au dessus de 100 km/h, la consommation mixte entre 100 et 50, et en dessous urbaine. * Par exemple, le modèle de FerrariF430 a les données suivantes : * consommations : * consoSurRoute= 13.3 litres par CENT_KM, * consoUrbaine=26.9 litres par CENT_KM, * consoMixte = 18.3 litres par CENT_KM * et le calcul de la consommation en fonction de la vitesse utilise la règle précédente qui donne les résultats comme : **(attention résultats faux.. il y a un décalage)** * A 150km/h Conso : [31.258333333333336 litres par CENT_KM]] avec un coefficient de coeff calculé de: 0.0013300000000000002 * A 90/h Conso : [17.045222222222222 litres par CENT_KM]] avec un coefficient calculé de : 0.00269 * A 30km/h Conso : [9.087666666666667 litres par CENT_KM]] - Quelle modélisation proposez-vous ? Quel est le couplage entre vos classes? Avez-vous bien supporté l'extension? Il existe plusieurs solutions possibles, c'est à vous de décider! (( Voici un code java dont vous pouvez vous inspirer, si besoin, en le simplifiant ! private double calculerCoeff(Vitesse v) { double coeff = Math.pow( 10, -4); //Au dessus de 100 km/h on prend en compte la consommation sur route que l'on multiplie par 10^-4, if (v.getValeur()>100){ return coeff*consoSurRoute.getValeur();} if (v.getValeur()>50) return coeff*consoMixte.getValeur(); return coeff*consoUrbaine.getValeur(); } )) Bien sûr les calculs précédents pour le modèle Clio restent vrais. Vos tests doivent donc continuer à être effectifs. ===== Responsabilité et Interfaces (20mn) ===== On veut définir un calculateur qui en fonction d'un modèle de voiture et d'une distance peut calculer : * la consommation à prévoir en fonction du type de route * Pour ma ferrari F430 si je roule pendant 100km sur route, combien vais-je dépenser d'essence? * la consommation à prévoir en fonction de la vitesse * Pour ma clio si je roule pendant 100km à 90km/h, combien vais-je dépenser d'essence? - On définit le calculateur comme une classe. - Quel est le couplage entre la classe calculateur et la classe modèle de voiture? ===== Bilan (10mn) ===== - Donc si on résume, voici des exemples de modèles : - A un modèle Clio, on associe des données de consommation fixes et un calcul de la consommation en fonction de la vitesse qui est basé sur un coefficient K donné, on fait pareil pour le modèle Mégane. - A un modèle Ferrari F430 on associe des données de consommation fixes et un calcul de la consommation en fonction de la vitesse qui est basé sur un coefficient K calculé, on fait pareil pour certaines Porshes. - Et bien sûr, le Berlingot, ... Pour tous évidemment on peut calculer la production de CO2. ===== Refactoring (30mn) (facultatif mais CONSEILLE) ===== En fait, pour certains modèles de voiture (par exemple, les Peugeots), les consommations moyennes sont obtenues par des requêtes à un service externe qui, en fonction des informations sur le modèle (on se limite au nom et à l'année, par exemple // Peugeot 208// et //2000//), nous renvoie une chaine de caractères au format JSON, par exemple ''{"consommation": {"route" : "6.3", "urbaine" : "8.1" } }''. - Intégrez ce type de "calcul" de la consommation dans votre modélisation. - Quel est l'impact? ((voir plus bas pour des détails techniques)) - Donc si on résume, en plus du bilan précédent : - A un modèle Mercedes ClasseS, on obtient les données de consommation en faisant appel à un service externe, et la consommation en fonction de la vitesse est basée sur un coefficient K calculé. - A un modèle Peugeot 208, on obtient les données de consommation en faisant appel à un service externe, et la consommation en fonction de la vitesse est basée sur un coefficient K donné; - Les modèles "Voitures du Peuple" trichent en renvoyant une production en CO2 divisée par 3, par exemple, Le Touran... - Si à présent on ajoute un autre mode de détermination de la consommation basée par exemple sur des données statistiques stockées dans un fichier excel, et que l'on décide que le modèle Clio se base sur ces données... Votre solution est-elle toujours valide? - Pour certains véhicules on veut pouvoir enregistrer une consommation en Galon pour 100 Miles, que devez-vous modifier? On ne vous demande pas de le faire. - Que retenez-vous? * Soit par mail avec Mme Lecat, soit sur le [[http://jalon.unice.fr/cours/blay/Cours-blay-20150930110548/BoiteDepot-blay-20151007231635810478?mode_etudiant=true&menu=depots|dépôt JALON]], pour Mme Blay : - Un document dont le titre est TDSOLID_ contenant * votre modèle final (Tout le monde n'aboutit pas au même modèle, c'est certain) . * des explications sur les raisons de ce modèle (dont vous êtes très fiers) et les leçons apprises. - Les codes et les tests. Pensez bien que le service externe ne doit pas être vraiment implémenté. Une fonction qui pour l'instant retourne à chaque fois la même chaine de caractère convient très bien, et vous pouvez considérer aussi la transformation d'une chaine de caractère JSON en "autre chose" comme donnée (par exemple : return new Consommation(...)). Pour ceux qui rendent la partie facultative, un **deuxième** rendu est possible le 2 novembre à 23h59 par mail (Cela n'exclut pas le 1e rendu.) Il fera dans ce cas, l'objet d'un "BONUS". ===== Suppléments (facultatifs pour les plus avancés) ===== - On associe des prix aux carburants, et on veut connaitre le cout d'un trajet en fonction d'un modèle de voitures - Pour les voitures electriques : la production de CO2 est à 0 et la consommation telle que définie précédemment est à 0 également mais par contre elles exposent un autre type de consommation.... sans le faire que changeriez vous dans votre modèle pour le prendre en compte. ==== Tuyaux ==== Vous pouvez utiliser la bibliothèque "Jackson" pour gérer le format JSON. Les . jar dont vous avez besoin :{{:2014_2015:s3:concprogobjet:td:jackson-databind-2.3.1.jar|}} {{:2014_2015:s3:concprogobjet:td:jackson-core-2.4.3.jar|}} {{:2014_2015:s3:concprogobjet:td:jackson-annotations-2.4.0.jar|}} Pour pouvoir les utiliser dans le projet Eclipse : Sur le projet > Properties > Java Build Path > Add external Jars et sélectionnez les. Pour transformer un objet Java en string Json : ObjectMapper objectMapper = new ObjectMapper(); objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false); Object json = objectMapper.readValue( objectMapper.writeValueAsString(cm), Object.class); String jsonString = objectMapper.writerWithDefaultPrettyPrinter() .writeValueAsString(json); return jsonString; Pour transformer une string Json en objet Java : //Appel fonction de votre code// String json = serviceExterne.consommationJSON(modele); ObjectMapper objectMapper = new ObjectMapper(); objectMapper.enableDefaultTyping(); //Nom de la classe cible dépendant de votre modèle, chez moi, c'est ConsommationMoyenne ConsommationMoyenne cm = objectMapper.readValue(json, ConsommationMoyenne.class); ==== Corrections ==== [[2015_2016:s3:concprogobjet:td:corrections:td2|Corrections TD2 : Bus]]