Exercices

Utilisation du type HashMap

La classe HashMap implante un dictionnaire qui permet de retrouver un objet de type V à partir d’une clef de type K. On a donc une classe avec deux paramètres-type.

Si vous avez réalisé l’exercice consistant à utiliser l’interface (qui consiste à rechercher un Vehicule à partir de sa référence)

package com.garaje.commons;
public interface CatalogueVehiculeSimple {
   /**
    * @param référence référence du véhicule cherché
    * @return null si véhicule pas trouvé
    */
   Vehicule get(String référence) ;
}

réaliser un autre "simulacre" (un code de test simplifié) implantant cette interface et qui permette de rechercher directement un Vehicule par sa référence (utiliser un HashMap).

Proposition de solution : Le catalogue de Vehicule (basé sur HashMap).

Définition de résultat de requête

Si vous avez réalisé l’exercice consistant à utiliser l’interface (qui consiste à rechercher un Vehicule à partir de sa référence) CatalogueVehiculeSimple ci-dessus ; nous allons modifier cette interface de plusieurs manières:

  • Le critère de recherche de la méthode get est un "masque" de recherche sur la marque du Vehicule: c’est une chaine simple qui représente tout ou partie de la marque (par exemple "tro" pour "Citroën").

  • Le résultat est un ensemble de Vehicules (plusieurs Vehicules peuvent avoir une marque qui correspond à ce critère de recherche). Quel type choisir pour représenter ce résultat?

  • Une méthode permet d’obtenir tous les véhicules disponibles.

A partir de ces contraintes :

  • Définir une nouvelle version de l’interface CatalogueVehicule

  • Réaliser un code simulacre qui implante cette interface.

Propositions de solution:

Définition d’une interface générique

Si vous avez réalisé l’exercice précédent (définition d’une interface pour le Catalogue de Vehicule) comment redéfinir cette interface de manière à ce que les services définis s’appliquent à un type quelconque? (on aurait alors la possibilité de définir un Catalogue de Livres, un Catalogue d’ArticleDeSport, etc….)

Proposition de solution:

Un Panier plus robuste

(Pour ceux qui ont commencé le projet de vente de livres)

Dans le projet "Oubangui.com" changer la réalisation du Panier. Au lieu d’utiliser un tableau de Livres utiliser une ArrayList.

  • mettre en place les méthodes ajouter(Livre l), retirer(Livre l) et getMontantTotal()

Une autre "vue" (Observer) sur le Garage

En conservant le code précédent dans lequel le garage est un Observable enregistrez un autre Observer auprès du Garage:

  • Celui-ci gérera des statistiques d’entrée (utiliser un HashMap): chaque fois que la "même" voiture entre au garage incrémenter un compteur ("même" signifie ici : même modèle). Faire une méthode toString() pour donner les statistiques générales.

  • Tester

Un autre type de Garage

(Exercice de révision)

En reprenant les exercices de conception de la précédente leçon mettre en oeuvre la gestion d'événement personnalisée qui s’appuie sur cette interface d'écoute:

package com.grandgarage.biz;
public interface EcouteStationnement {
   public void entrée(EvenementStationnement evt) ;
   public void sortie(EvenementStationnement evt) ;
}

et sur cet événement:

package com.grandgarage.biz;

import java.util.EventObject;

public class EvenementStationnement extends EventObject {

   public final Vehicule vehiculeConcerné ;
   public final long estampilleHoraire = System.currentTimeMillis();

   public EvenementStationnement(Stationnement stationnement, Vehicule voiture) {
      super(stationnement) ;
      this.vehiculeConcerné = voiture ;
   }

   /**
    * cas très intéressant:
    * <UL>
    * <LI> covariance sur la méthode <TT>getSource()</TT>
    * <LI> utiisation d'un champ protected de EventObject
    * </UL>
    * @return
    */
   @Override
   public Stationnement getSource() {
      return (Stationnement) this.source ;
   }

   @Override
   public String toString(){
      //TODO : faire mieux!
      return this.vehiculeConcerné.toString();
   }

}
  • reécrire un Garage qui implante concrètement cette interface:

package com.grandgarage.biz;
public interface Stationnement {
   public int garer(Vehicule vehicule) throws ExceptionContenance ;
   public int retirer(Vehicule vehicule) ;
   public int disponibilités() ;
}

et qui permet d’enregistrer des écouteurs. (Utiliser une ArrayList)

  • Tester en écrivant un Vehicule simple (comme Moto) et un écouteur simple qui affiche le véhicule entré et le nombre de places libres.

Propositions de corrigés:

Exemples

Utilisation du type HashMap

package com.garaje.simulacres;

import com.garaje.commons.CatalogueVehiculeSimple;
import com.garaje.commons.Vehicule;
import com.garaje.deploy.Moto;
import com.garaje.deploy.Voiture;
import java.util.HashMap;
public class PseudoCatalogueSimple2 implements CatalogueVehiculeSimple {
   static Vehicule[] tableauBidon = {
      new Voiture("EZ44", "Wartburg", "1020", 425,220),
      new Moto("HHX", "Mamuth", "986", 160, 120),
      //etc, etc...
   } ;

   private HashMap<String,Vehicule> dict =
      new HashMap<String,Vehicule>() ;

   public PseudoCatalogueSimple2() {
      for(Vehicule vehicule : tableauBidon) {
         dict.put(vehicule.getRef(), vehicule) ;
      }
   }

   @Override
   public Vehicule get(String référence) {
      return dict.get(référence );
   }
}

Définition de résultat de requête

package com.garaje.commons;

import java.util.Iterator;

public interface CatalogueVehicule2 extends Iterable<Vehicule>{

   // autres méthodes (voir par exemple CatalogueVehicule et critère de recherche)
   Iterator<Vehicule> get(String masqueMarque);
}
package com.garaje.simulacres;

import com.garaje.commons.CatalogueVehicule2;
import com.garaje.commons.Vehicule;
import com.garaje.deploy.Moto;
import com.garaje.deploy.Voiture;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;

public class PseudoCatalogue2 implements CatalogueVehicule2 {

   static Vehicule[] tableauBidon = {
      new Voiture("EZ44", "Wartburg", "1020", 425, 220),
      new Moto("HHX", "Mamuth", "986", 160, 120), //etc, etc...
   };

   public Vehicule[] getVehicules() {
      return tableauBidon ;
   }
   private List<Vehicule> liste = Arrays.asList(getVehicules());

   @Override
   public Iterator<Vehicule> get(String masqueMarque) {
      ArrayList<Vehicule> res = new ArrayList<Vehicule>();
      for (Vehicule vehicule : liste) {
         // serait plus performant de simplement parcourir le tableau
         // ceci est juste pour exemple
         if (vehicule.getMarque().contains(masqueMarque)) {
            res.add(vehicule);
         }
      }
      return res.iterator();
   }

   @Override
   public Iterator<Vehicule> iterator() {
      return liste.iterator();
   }
}
package com.garaje.ihm;

import com.garaje.commons.CatalogueVehicule2;
import com.garaje.commons.Vehicule;
import java.io.Console;
import java.util.Iterator;

/**
 *
 * Peut être reécrit avec interaction JSHELL
 */
public class SimpleIHMCatalogue2 { // implements Runnable!
   private CatalogueVehicule2 catalogue ;
   private Console console ;

   public SimpleIHMCatalogue2(CatalogueVehicule2 catalogue) {
      this.catalogue = catalogue;
      this.console = System.console() ;
      if(this.console == null ){
         throw new RuntimeException("no Console!") ;
      }

   }

   public void run() {
      String question = null ;
      while(null != (question = this.console.readLine("masque marque : "))) {
         Iterator<Vehicule> trouvés = catalogue.get(question);
         while(trouvés.hasNext()) {
            this.console.printf("trouvé : %s\n", trouvés.next());
         }
      }
   }
}
package com.garaje.tests;

import com.garaje.commons.CatalogueVehicule2;
import com.garaje.ihm.SimpleIHMCatalogue2;
import com.garaje.simulacres.PseudoCatalogue2;

/**
 * p.e interaction JShell
 */
public class MainSimple2 {
   public static void main(String[] args) {
      CatalogueVehicule2 catalogue =
         new PseudoCatalogue2() ;
      SimpleIHMCatalogue2 ihm = new SimpleIHMCatalogue2(catalogue) ;
      ihm.run() ;
   }
}

Définition d’une interface générique

package com.garaje.commons;

import java.util.Iterator;

public interface Catalogue<T> extends Iterable<T> {
   Iterator<T> get(String requête);
   /*
    * plus fort:
    * Iterator<T> get(CritereChoix<T> critère) ;
    * avec:
    * public interface CritereChoix<X> {
    *    boolean choisir(X selection) ;
    *    public String toString() ;
    * }
    */
}

Un Panier plus robuste

package com.oubangui.biz2;

import java.util.ArrayList;
import java.util.Collections;

public class Panier2 {
// MEMBRES :  CHAMPS
      // ID si persistant
      //
      // immuable,  peut êre null
   private Client  client ;

      //technical data

   private ArrayList<Livre> contenu = new ArrayList<>();
   // lire la doc de Collections!
   private ArrayList<Livre> vueContenu = Collections.unmodifiableList(contenu) ;

   // CONSTRUCTEURS
   // cosntructeur par défaut ici

   // MEMBRES : ACCESSEURS/MUTATEURS
   public Client getClient() { return this.client ; }
   public void setClient(Client cli) {
      this.client = cli;
   }

   // MODIFICATEURS, SERVICES
   public void ajouter(Livre livre) throws ExceptionStock {
       livre.retirerDuStock(1);
      // ATTENTION NON ATTEINT EN CAS DE PROPAGATION D'EXCEPTION
       contenu.add( livre) ;
   }

    /**
     * Pour simplifier: pas d'exception ou de résultat
     * pour indiquer qu'on cherche à supprimer un Livre non présent
     * dans le Panier.
     * @param livre
      */
    public void retirer(Livre livre) {
        if(contenu.remove(livre)) {
            livre.rajouterAuStock(1);
        }
     }

        /**
         * Dispositif critique pour ne pas casser l'encapsulation
    */
   public ArrayList<Livre> getContenu() {
      return vueContenu;
   }

    /**
     * typiquement le montant total est un "attribut calculé".
     * @return
     */
     public double getMontantTotal() {
         double res = 0. ;
         for(Livre livre: contenu) {
             res += livre.getPrix();
         }
         return res ;
     }
    @Override
   public String toString(){
        String res = " --- Panier ---\n";
        // utiliser un StringBuilder!!
        // ou plus simplement rajouter contenu.toString()
         for(Livre bk : contenu){
            res += bk.toString() + '\n'  ;
         }
         return res ;
   }
}

Une autre "vue" (Observer) sur le Garage

package com.grandgarage.biz;

import java.util.HashMap;
import java.util.Observable;
import java.util.Observer;

import static java.awt.Color.*;
import static java.lang.System.Logger.Level.*;

public class StatsGarageD implements Observer {

    private HashMap<String, Integer> stats = new HashMap<String, Integer>();

    public void update(Observable arg0, Object arg1) {
        EvenementGarage evt = (EvenementGarage) arg1;
        String modèle = evt.véhicule.getModèle();
        Integer nombre = stats.get(modèle);

        switch (evt.mouvement) {
            case SORTIE:
                if (nombre != null) { // pour simplifier
                    // on ne fiat pas de controle de coherence
                    // on pourrait faire une assertion!)
                    stats.put(modèle, --nombre);
                    // on pourrait également détruire l'entrée si plus de voiture
                    // de ce modèle
                }
                break;
            case ENTREE:
                if (nombre == null) {
                    stats.put(modèle, Integer.valueOf(1));
                } else {
                    // ATTENTION: autoboxing/unboxing! ne pas abuser!
                    stats.put(modèle, ++nombre);
                }
                break;
        }
    }

    @Override
    public String toString() {
        return stats.toString();
    }

    public static void main(String[] args) {
        try {
            int taille = 50;
            GarageD garage = new GarageD(taille);
            garage.addObserver(new Panneau2GarageD());
            StatsGarageD stats = new StatsGarageD();
            garage.addObserver(stats);
            garage.addObserver(new PanneauGarageD());
            garage.garer(new VoitureV4("34RT34", "verso", 11567.56, GRAY));
            // polymorphisme
            VoitureV4 voiture = new VoitureAncienneV4("35RT34", "datsun", 11567.56, GRAY, 1945);
            garage.garer(voiture);

            garage.garer(new VoitureAncienneV4("33?RY45", "micra", 11567.56, GRAY, 1985));
            System.out.println("Stats " + stats);
            garage.retirer(voiture);
            System.out.println("Stats " + stats);
        } catch (ExceptionContenance ex) {
            System.getLogger("com.grandgarage.biz").log(ERROR, "garage plein", ex);
        }
    }
}

Un autre type de Garage

package com.grandgarage.biz;

import java.util.ArrayList;

public class GarageVehicules implements Stationnement {
   //TODO protéger contre  les accès concurrents!!!
   // sera un CopyOnWriteArrayList!
   private ArrayList<EcouteStationnement> écouteurs =
      new ArrayList<EcouteStationnement>() ;
   private Vehicule[] parking;
   private int nbVehicules;
   private int tailleParking;

   public GarageVehicules(int taille) {
      //TODO on pourrait controler la taille !
      this.tailleParking = taille;
      parking = new Vehicule[taille];
   }

   public void addEcouteur(EcouteStationnement ecoute) {
      écouteurs.add(ecoute) ;
   }
   public void removeEcouteur(EcouteStationnement ecoute){
      écouteurs.remove(ecoute) ;
   }
   @Override
   public int garer(Vehicule véhicule) throws ExceptionContenance {
      // le parking est-il plein?
      if (this.nbVehicules >= this.tailleParking) {
         throw new ExceptionContenance(this, véhicule);
      }
      for (int index = 0; index < parking.length; index++) {
         if (null == parking[index]) {
            parking[index] = véhicule;
            this.nbVehicules++;
            EvenementStationnement evt = new EvenementStationnement(this, véhicule) ;
            for(EcouteStationnement ecoute : écouteurs) {
               ecoute.entrée(evt);
            }
            return index;
         }
      }
      return -1; // anomalie!!!!
      // on prévient les parties intéressées

   }

   @Override
   public int retirer(Vehicule véhicule) {
      for (int ix = 0; ix < parking.length; ix++) {
         if (véhicule.equals(parking[ix])) {
            parking[ix] = null;
            nbVehicules--;
            EvenementStationnement evt = new EvenementStationnement(this, véhicule) ;
            for(EcouteStationnement ecoute : écouteurs) {
               ecoute.sortie(evt);
            }
            return ix;
         }
      }
      return -1;
   }

   @Override
   public int disponibilités() {
      return this.tailleParking - this.nbVehicules;
   }
}
package com.grandgarage.biz;

import java.awt.Dimension;

public class Moto extends Vehicule {

   public Moto(String reférence, String modèle, double prixHT, Dimension empattement) {
      super(reférence, modèle, prixHT, empattement);
   }

   @Override
   public double getTauxTVA() {
      // TODO :lire dans une ressource
      return 1.196 ;
   }

   @Override
   public String getType() {
      // un peu stupide!
      return this.getClass().getSimpleName() ;
   }
}
package com.grandgarage.biz;
public class AffichageStationnement implements EcouteStationnement {

   @Override
   public void entrée(EvenementStationnement evt) {
      System.out.println(" ENTREE DE : " + evt);
      System.out.println(" plus que : " + evt.getSource().disponibilités()
         + " place(s) libre(s)");
   }

   @Override
   public void sortie(EvenementStationnement evt) {
      System.out.println(" SORTIE DE : " + evt);
      System.out.println(" plus que : " + evt.getSource().disponibilités()
         + " place(s) libre(s)");
   }

}
package com.grandgarage.biz;

import java.awt.Dimension;

public class TestGarageVehicules {
   public static void main(String[] args) throws Exception {
      GarageVehicules garage = new GarageVehicules(30) ;
      garage.addEcouteur(new AffichageStationnement());
      Moto moto = new Moto("GHK235", "PowerGlide", 5789.78, new Dimension(70,145)) ;
      garage.garer(moto );
      garage.retirer(moto);
   }

}