exercices

essai de définition différentielle

Déplacer le code de Voiture vers un package comme com.grandgarage.biz.

Créer une classe VoitureAncienne. Une VoitureAncienne est une Voiture avec une information supplémentaire : l’année de construction (c’est un élément de gestion qui sera utilisé ultérieurement pour la taxation).

De quelles informations avez-vous besoin pour "créer" une "voiture ancienne" dans le catalogue du garage? Donc comment sera défini la signature du constructeur de VoitureAncienne?

Avec les informations techniques Java dont vous disposez votre code ne se compilera pas …

Comprendre pourquoi!

constructeur dans classe "fille"

Maintenant modifiez le code du constructeur de VoitureAncienne de façon à ce qu’il se compile.

Spécialisation

Une VoitureAncienne sera taxée différemment.

  • Modifier le code de Voiture et définir une méthode double getTauxTaxe() Utiliser cette méthode pour calculer le prix rendu au consommateur.

  • spécialiser cette méthode dans VoitureAncienne et modifier le taux de taxation.

  • Tester ces codes.

  • Un code de Voiture

  • un code pour Voiture Ancienne (avec un calcul amusant de la taxe)

Maintenant un autre exercice: la société com.locz gère des VoitureDeLocation. Une voiture de location aura des méthodes comme getModèle, getCouleur et aussi getPrixJournée (pour avoir le coût de location à la journée.

Ecrire un code (simplifié) de VoitureDeLocation

Polymorphisme

Utiliser la classe Garage dans un test et garer non seulement des Voitures mais aussi des VoitureAnciennes.

  • On notera que la classe Garage est antérieure à la classe VoitureAncienne et pourtant tout fonctionne correctement! (on constate ainsi la puissance du polymorphisme)

  • un code pour le Garage (le test est intégré au corrigé mais ce ne doit pas être le cas dans vos sources)

Evaluation dynamique

L’idée générale: les voitures ne sont pas toutes taxées de la même manière. Les Voitures ont une méthode getPrixTTC() qui calcule le prix à partir du prix H.T. et du résultat d’une méthode getTauxTVA().

  • Modifier le code de Voiture afin de correspondre à ce schéma

  • Modifier le code de VoitureAncienne : ici le taux de TVA est différent.

Exécuter le test précédent avec getValeur() de la classe Garage: bien examiner la façon dont les méthodes sont invoquées.

Pour une solution voir les corrigés de l’exercice suivant sur les Voitures.

Conception

(exercice de révision à réaliser ultérieurement)

Suite à la libéralisation de la poste de la république de Poldévie Orientale une nouvelle société se crée pour expédier le courrier au niveau national uniquement.

On peut envoyer des lettres suivant ce tarif progressif (les tarifs sont en Roublons Poldèves bien entendu!):

  • jusqu'à 20 grammes : 3

  • jusqu'à 50 grammes : 4.5

  • jusqu'à 100 grammes : 6.7

  • jusqu'à 250 grammes : 11.5

  • jusqu'à 500 grammes : 16

  • jusqu'à 1000 grammes : 21

  • jusqu'à 2000 grammes : 28

  • jusqu'à 3000 grammes : 33

(on ne prend pas de lettres de plus de 3kg!)

Une lettre a donc un poids et une adresse et on peut calculer son prix.

Il y a aussi des Lettres recommandées. La facturation varie en fonction du poids (comme pour une lettre) et d’un facteur dépendant du "taux de recommandation" : R1 = 1,12 ; R2 = 1,22 ; R3 = 1,33 .

Une "Lettre recommandée avec accusé de réception" est facturée de même et on rajoute 3 au prix. (Cette lettre comporte une adresse retour).

Ecrire un code d’agent posteur simplifié qui affiche la lettre que l’on poste (son poids, son prix, etc..) et affiche au fur et à mesure le montant total des lettres expédiées.

propositions de solutions : ICI , ICI , utilise ce code , ICI aussi,

Specialisation de méthodes de Object

Modifier la classe Voiture et écrire une méthode equals spécifique.

Pour simplifier outrageusement nous dirons que deux voitures sont "égales" si elles ont le même identifiant (on rajoutera ce champs dans la définition de Voiture et de VoitureAncienne).

  • Si vous utilisez un IDE il y a de bonnes chances que celui-ci vous suggère de créer une méthode int hashCode(). Si l’IDE peut la générer automatiquement laissez le faire: le rôle de cette méthode sera expliqué si vous faites la leçon sur les structures de données de type HashMap.

  • écrire un code de Test qui compare deux Voitures et qui compare deux VoitureAnciennes.

  • modifier le code de Garage : pour "garer" une voiture on cherche la première place libre, pour la retirer on invoquera la méthode int retirer(Voiture voitureAretirer) et donc on compare la voiture demandée à celles qui sont garées (ne pas oublier de mettre à null l’emplacement correspondant!)

Les modules et les conditions d’import/export

Voici venir le moment d’expérimenter une architecture avec des modules.

  • créer un module qui soit (par exemple) de nom: +com.maboite.monapp.

  • dans ce module créer le package de nom com.maboite.monapp.ihm

  • dans ce package recopier cette classe (il n’est pas fondamentalement nécessaire de savoir ce qu’elle fait) :

    package com.maboite.monapp.ihm;
    
    import javax.swing.*;
    
    public class DemoFenetre extends JFrame {
        private JLabel label ;
    
        public DemoFenetre(String message) {
            this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            label = new JLabel(message);
            this.add(label) ;
    
        }
    }

    Ce code fait appel au package javax.swing (graphique) qui est dans le module standard java.desktop

  • créer un deuxième module de nom com.maboite.appclient

  • dans ce module créer le package com.maboite.appclient.usegui

  • dans ce package recopier ce code:

    package com.maboite.appclient.usegui;
    
    import com.maboite.monapp.ihm.DemoFenetre;
    
    public class SimpleMainGui {
        public static void main(String[] args)
        {
            String message = "<html> <B>Santiago du Chili </B>" +
            " <br> Pharmacies de garde : " +
            "<UL><LI> Pharmacie Lopez!     </LI> </UL> </html>" ;
            DemoFenetre fenetre = new DemoFenetre(message) ;
            //méthodes de la class JFrame
            fenetre.pack() ;
            fenetre.setVisible(true);
        }
    
    }

    On remarquera que ce code utilise des méthodes héritées de la classe JFrame

Maintenant pour lancer ce dernier main écrire correctement les deux module-info.java de ces modules.

Que concluez vous?

Maintenant modifiez les codes de la manière suivante:

package com.maboite.monapp.ihm;

import javax.swing.*;

public class DemoFenetre extends JFrame {
    private JLabel label ;

    public DemoFenetre(String message) {
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        label = new JLabel(message);
        this.add(label) ;

    }

    public JLabel getMessage() {
        return label ;
    }
}

et:

package com.maboite.appclient.usegui;

import javax.swing.JLabel ;

import com.maboite.monapp.ihm.DemoFenetre;

public class SimpleMainGui {
    public static void main(String[] args)
    {
        String message = "<html> <B>Santiago du Chili </B>" +
        " <br> Pharmacies de garde : "+
        " <UL><LI> Pharmacie Lopez!     </LI> </UL> </html>" ;
        DemoFenetre fenetre = new DemoFenetre(message) ;
        //méthodes de la class JFrame
        fenetre.pack() ;
        fenetre.setVisible(true);
        JLabel label = fenetre.getMessage() ;
        System.out.println(label) ;
    }

}

Comment modifier le premier module-info.java ?

Vos conclusions?

Refaire les tests en revenant à la première version de module-info et en modifiant le code de SimmpleMainGui en remplaçant le type JLabel par Object et en supprimant import javax.swing.*.

Vos conclusions?

Encore un effort pour conforter les conclusions précédentes: nous allons créer dans le module com.maboite.monapp un package com.maboite.monapp.noexport … qui n’apparaîtra pas dans les directives exports du module-info

Dans ce package écrire le code suivant:

package com.maboite.monapp.noexport;

import java.util.EventObject;

public class Fantome  extends EventObject {
    public Fantome(Object source) {
        super(source);
    }
    public String toString() {
        return super.toString() + "je suis un Fantome!" ;
    }
}

Modifier le code de SimpleMainGui en rajoutant ces deux lignes:

  EventObject evt = fenetre.getFantome() ;
  System.out.println(evt);

Exécuter le code … Les explications précédentes seront toujours valides: un code dont le type n’est pas accessible peut, tout de même, être exécuté!

Exemples

constructeur dans classe "fille"

package com.grandgarage.biz;

public class VoitureV1 {
   private final String référence ;
   private final String modèle ;
   private double prixHT ;
   private java.awt.Color couleur;

   /*  Pour les besoins de l'exercice seulement
    * en effet le taux de TV peut changer
    * et on ne devrait pas avoir à modifier ce code
    * en pratique ce taux est ce qu'on appelle une "ressource"
    * et il faudra apprendre à la configurer.
    */
   public static double TAUX_TVA = 1.235 ;


   public VoitureV1 (String ref, String md, double px) {
      this(ref,md,px, java.awt.Color.LIGHT_GRAY);
   }

   public VoitureV1 (String ref ,String md, double px, java.awt.Color col) {
      this .référence= ref ;
      this.prixHT = px ;
      this.modèle = md ;
      this.couleur = col ;
   }

   public String getRéférence() {
      return this.référence ;
   }
   public String getModèle() {
      return this.modèle ;
   }

   public java.awt.Color getCouleur() {
      return this.couleur ;
   }

   public double getPrixTTC() {
      return Math.rint(this.prixHT *  TAUX_TVA) ;
   }

   /** prixHT est le seul champ modifiable!
    * @param prixHT
    */
   public void setPrix(double prix) {
      this.prixHT = prix ;
   }

   public String toString() {
      return this.référence
         + " " + this.modèle ;
   }


   //////////////////////////////////////////////////////////
   public static void main(String[] args) {
      VoitureV1 rosalie = new VoitureV1("ref456", "verso", 11567.56, java.awt.Color.GRAY) ;
      System.out.println(rosalie.getPrixTTC()) ;

   }
}
package com.grandgarage.biz;

public class VoitureAncienneV1  extends VoitureV1{
    private int année;

    public VoitureAncienneV1(String ref, String modèle, double prix, int année) {
        super(ref, modèle, prix) ;
        this.année = année ;
    }
}

Spécialisation

package com.grandgarage.biz;
import java.awt.Color ;
import static java.awt.Color.* ;


public class VoitureV2 {
   private final String référence ;
   private final String modèle ;
   private double prixHT ;

   private Color couleur  ;

   /*  Pour les besoins de l'exercice seulement
    * en effet le taux de TV peut changer
    * et on ne devrait pas avoir à modifier ce code
    * en pratique ce taux est ce qu'on appelle une "ressource"
    * et il faudra apprendre à la configurer.
    */
   public static double TAUX_TVA = 1.235 ;


   public VoitureV2 (String ref, String md, double px) {
      this(ref, md, px, BLACK);

   }

   public VoitureV2 (String ref, String md, double px, java.awt.Color col) {
      this.référence = ref;
      this.prixHT = px ;
      this.modèle = md ;
      this.couleur = col ;
   }

   public String getModèle() {
      return this.modèle ;
   }

   public java.awt.Color getCouleur() {
      return this.couleur ;
   }

   public double getPrixTTC() {
      return Math.rint(this.prixHT *  this.getTauxTaxe()) ;
   }

   public double getTauxTaxe(){
       return TAUX_TVA ;
   }

   /** prixHT est le seul champ modifiable!
    * @param prixHT
    */
   public void setPrix(double prix) {
      this.prixHT = prix ;
   }

   public String toString() {
      return this.référence
         + " " + this.modèle ;
   }

}
package com.grandgarage.biz;
import java.awt.Color ;
import static java.awt.Color.* ;

public class VoitureAncienneV2  extends VoitureV2{
    private int année ;

    public VoitureAncienneV2(String ref, String md, double prix, Color col, int année) {
        super(ref, md, prix, col);
        this.année = année ;
    }

    /**
     *  Une logique très complexe: typiquement ceci
     * est un code de déploiement susceptible d'être modifié
     * quand les règles de gestion changent
     */
    @Override
    public double getTauxTaxe() {
        if(année > 1970) { return super.getTauxTaxe() ; }
        if(année < 1920) { return 1 ;}
        double tauxNormal =  super.getTauxTaxe() - 1;
        //
        double ratio = (1970 - this.année) * 0.02 ;
        return 1 + (tauxNormal *  ratio) ;
    }

       //////////////////////////////////////////////////////////
   public static void main(String[] args) {
      VoitureV2 maVoiture = new VoitureV2("ref425", "verso", 11567.56, GRAY) ;
      System.out.println(maVoiture.getPrixTTC()) ;
      VoitureAncienneV2 maCharette = new VoitureAncienneV2("678", "datsun", 11567.56, GRAY, 1945) ;
      VoitureAncienneV2 monAntiquité = new VoitureAncienneV2("456", "micra", 11567.56, GRAY, 1985) ;
      System.out.println(maCharette.getPrixTTC()) ;
      System.out.println(monAntiquité.getPrixTTC()) ;

   }

}
package com.locz.biz;
import java.awt.Color ;
import com.grandgarage.biz.*;

public class VoitureDeLocation {
   private double prixJournée;
   private VoitureV2 déléguée ;
   public VoitureDeLocation(VoitureV2 voiture, double prixJournée) {
      this.déléguée = voiture ;
      this.prixJournée = prixJournée;
   }
   public double getPrixJournée(){
      return this.prixJournée ;
   }
   public void setPrixJournée(double prix){
        this.prixJournée = prix
   }
   public String getModèle() {
      return déléguée.getModèle() ;
   }
   public Color getCouleur() {
      return déléguée.getCouleur() ;
   }
}

On notera: - que l’on est dans une perspective différente de celle de la gestion des voitures pour le garage. - que les outils IDE ont des facilités pour créer rapidement ce genre de délégation - qu’on peut louer une voiture ancienne (voir ci-après polymorphisme)!

Polymorphisme

package com.grandgarage.biz;

import java.util.Arrays;
import static java.awt.Color.*;

public class GarageA1 {

   private VoitureV2[] parking;
   private int nbPlacesLibres;

   public GarageA1(int nbPlaces) {
      parking = new VoitureV2[nbPlaces];
      this.nbPlacesLibres = nbPlaces;
   }

   // une version plus réaliste
   public void garer(VoitureV2 voiture) {
      for (int ix = 0; ix < parking.length; ix++) {
         if (parking[ix] == null) {
            parking[ix] = voiture;
            nbPlacesLibres--;
            break;
         }
      }
   }

   public double getValeur() {
      double res = 0;
      for (VoitureV2 emplacement : parking) {
         if (emplacement != null) {
            res += emplacement.getPrixTTC();
         }
      }
      return res;
   }

   public String toString() {
      return Arrays.toString(parking);
   }

   public static void main(String[] args) {
      GarageA1 garage = new GarageA1(10);
      garage.garer(new VoitureV2("hj456", "verso", 11567.56, GRAY));
      // polymorphisme
      garage.garer(new VoitureAncienneV2("hj457", "datsun", 11567.56, GRAY, 1945));
      garage.garer(new VoitureAncienneV2("hj458", "micra", 11567.56, GRAY, 1985));
      System.out.println(garage.getValeur());
   }
}

Conception

package com.macposte.courrier;

/** une lettre.
 * <P> pour calculer le tarif d'affranchissemnt on utilise
 * un tableau statique pour exprimer une fonction du poids
 *  (on pourrait adopter une autre stratégie -penser à la maintenance-)
 */
public class Lettre {
    /* Merci à Y. Aharonowitz pour cet exercice
     * (initialement nommé "la poste eskimo")
     */

    private int poidsGramme; //public final int poidsGramme ;

    private String adresse; //public final Adresse adresse ;

    private static int[] poids = {20, 50, 100, 250, 500, 1000, 2000, 3000};
    private static double[] tarifs = {3, 4.50, 6.70, 11.50, 16, 21, 28, 33,};
    //
    private static double MAX_PRIX = 33;

    /**
     * devrait être Lettre(int poids, Adresse adresse)
     * @param poids
     * @param adr
     */
    public Lettre(int poids, String adr) {
        // normalement on devrait verifier si on ne depasse pas
        // les limites <0 >3000g
        poidsGramme = poids;
        adresse = adr;
    }// End Lettre(int, String)

    public double getPrix() {
        for (int ix = 0; ix < poids.length; ix++) {
            if (poidsGramme <= poids[ix]) {
                return tarifs[ix];
            }
        }
        return MAX_PRIX; // stupide nous verrons ultérieurement un mécanisme d'erreur

    }// End getPrix

    /**
     * devrait être Adresse getAdresse
     */
    public String getAdresse() {
        return adresse;
    }

    public int getPoids() {
        return poidsGramme;
    }

    public String toString() {
        return this.getClass().getSimpleName() + ": " +
                "poids=" + poidsGramme +
                ";prix=" + getPrix() +
                ";\nadresse=" + adresse + " ";
    }
}
package com.macposte.courrier;

/**
 *
 * @author pbamade
 */
public class LettreRecommandee  extends Lettre {
    private TauxRecommandation taux ;

    public LettreRecommandee(int poids, String adresse, TauxRecommandation taux) {
        super(poids, adresse);
        this.taux = taux ;
    }

    @Override
    public double getPrix() {
        return Math.rint(super.getPrix() * this.taux.getTaux()*100) /100 ;
    }

    public TauxRecommandation getTaux() { return this.taux ; }

    public String toString() {
        return " " + super.toString() + "tauxR:"+ this.taux ;
    }

}
package com.macposte.courrier;

/**
 *
 * @author pbamade
 */
public enum TauxRecommandation {

     R1(1.12), R2(1.22), R3(1.33);

    private double taux ;
    private TauxRecommandation(double taux) {
        this.taux = taux ;
    }

    public double getTaux() {
        return this.taux ;
    }

}
package com.macposte.courrier;

/**
 *
 * @author pbamade
 */
public class LettreRecommandeeAR extends LettreRecommandee {

    private String adresseRetour;
    public static final double SURCHARGE = 3.;

    public LettreRecommandeeAR(int poids, String adresse, TauxRecommandation taux, String adrRetour) {
        super(poids, adresse, taux);
        this.adresseRetour = adrRetour;
    }

    @Override
    public double getPrix() {
        return super.getPrix() + SURCHARGE;
    }

    public String getAdresseRetour() {
        return this.adresseRetour;
    }

    @Override
    public String toString() {
        return super.toString() + " adr retour: " + this.adresseRetour;
    }
}
package com.macposte.courrier;
import static com.macposte.courrier.TauxRecommandation.* ;
/**
 * très simplifié : affiche juste le montant total de ce qui est posté.
 * Encore un objet Simulacre qui ne fait rien ....
 *
 */
public class AgentPosteur {
    private int poidsTotal = 0 ;
    private double prixTotal = 0 ;

    public void poster(Lettre lettre) {
        poidsTotal += lettre.getPoids() ;
        prixTotal += lettre.getPrix() ;
        System.out.println(" on Poste :" + lettre);
        System.out.println(" poids total: " + this.poidsTotal + " prix total " + this.prixTotal);
    }

    public static void main(String[] args) {
        AgentPosteur postier = new AgentPosteur() ;

        postier.poster(new Lettre(10, "Mlle Mimi; Mimizan; 40"));
        postier.poster(new LettreRecommandee(180, "direction des Impots; Le Tampon ;réunion", R3));
        postier.poster(new LettreRecommandeeAR(30,"boite à malices; ", R1, "chez moi"));
    }
}

Specialisation de méthodes de Object

package com.grandgarage.biz;

import java.awt.Color;
import static java.awt.Color.*;

public class VoitureV3 {

   private String id;
   private String modèle;
   private double prixHT;
   private Color couleur;
   /*  Pour les besoins de l'exercice seulement
    * en effet le taux de TVA peut changer
    * et on ne devrait pas avoir à modifier ce code
    * en pratique ce taux est ce qu'on appelle une "ressource"
    * et il faudra apprendre à la configurer.
    */
   public static double TAUX_TVA = 1.235;

   public VoitureV3(String id, String md, double px) {
      this(id, md, px, BLACK);

   }

   public VoitureV3(String id, String md, double px, java.awt.Color col) {
      this.id = id;
      this.prixHT = px;
      this.modèle = md;
      this.couleur = col;
   }

   public String getId() {
      return this.id;
   }

   public String getModèle() {
      return this.modèle;
   }

   public java.awt.Color getCouleur() {
      return this.couleur;
   }

   public double getPrixTTC() {
      return Math.rint(this.prixHT *  this.getTauxTaxe()) ;
   }

   public double getTauxTaxe() {
      return TAUX_TVA;
   }

   /** prixHT est le seul champ modifiable!
    * @param prixHT
    */
   public void setPrix(double prix) {
      this.prixHT = prix;
   }

   public String toString() {
      return this.id
         + " " + this.modèle;
   }

   /**
    * on suppose ici qu'on n'a pas d'incohérence (deux voitures
    * avec des caractéristiques différentes qui ont la même référence!)
    * @param autre
    * @return
    */
   @Override
   public boolean equals(Object autre) {
      return (autre instanceof VoitureV3)
         && (((VoitureV3) autre).id.equals(this.id));
   }

   @Override
   public int hashCode() {
      // algorithme complexe de Hash (généré par NetBeans)
      // int hash = 97 * 7 +  this.modele.hashCode() );
      return this.id.hashCode();
   }
}
package com.grandgarage.biz;
import java.awt.Color ;
import static java.awt.Color.* ;

public class VoitureAncienneV3  extends VoitureV3{
    private int année ;

    public VoitureAncienneV3(String id, String md, double prix, Color col, int année) {
        super(id, md, prix, col);
        this.année = année ;
    }

    /**
     *  Une logique très complexe: typiquement ceci
     * est un code de déploiement susceptible d'être modifié
     * quand les règles de gestion changent
     */
    @Override
    public double getTauxTaxe() {
        if(année > 1970) { return super.getTauxTaxe() ; }
        if(année < 1920) { return 1 ;}
        double tauxNormal =  super.getTauxTaxe() - 1;
        //
        double ratio = (1970 - this.année) * 0.02 ;
        return 1 + (tauxNormal *  ratio) ;
    }
     public String toString() {
      return  super.toString()
         + " " + this.année;
     }

       //////////////////////////////////////////////////////////
   public static void main(String[] args) {
      VoitureV3 maVoiture = new VoitureV3("123DG56","verso", 11567.56, GRAY) ;
      VoitureAncienneV3 monAntiquité = new VoitureAncienneV3("345KL34", "datsun", 885, GRAY, 1945) ;
      VoitureAncienneV3 monAntiquité2 = new VoitureAncienneV3("346KL34","datsun", 11567.56, GRAY, 1985) ;
      System.out.println ("égalité ? " + (maVoiture.equals(monAntiquité)));
      // relire les commentaires sur la sémantique de égalité
       System.out.println ("égalité ? " + (monAntiquité.equals(monAntiquité2)));

     }

}
package com.grandgarage.biz;

import java.util.Arrays;
import static java.awt.Color.*;

/**
 *
 * @author pbamade
 */
public class GarageB {
   // la taille devrait être un argument du constructeur

   private VoitureV3[] parking;
   private int nbPlacesLibres;

   public GarageB(int nbPlaces) {
      parking = new VoitureV3[nbPlaces];
      this.nbPlacesLibres = nbPlaces;
   }

   /** privisoiremenr : rend -1 si pas de place
    * on verrra ultérieurement qu'il ne faut pas faire ça!
    * @param voiture
    * @return
    */
   public int garer(VoitureV3 voiture) {
      if (nbPlacesLibres == 0) {
         return -1;
      }
      for (int index = 0; index < parking.length; index++) {
         if (null == parking[index]) {
            parking[index] = voiture;
            nbPlacesLibres--;
            return index;
         }
      }
      return -1;
   }

   /**
    * le fait de rendre un int est provisoire
    * @param voiture
    * @return numero de place libre, -1 si pas présent
    */
   public int retirer(VoitureV3 voiture) {
      for (int ix = 0; ix < parking.length; ix++) {
         if (voiture.equals(parking[ix])) {
            parking[ix] = null;
            nbPlacesLibres++;
            return ix;
         }
      }
      return -1;
   }

   public double getValeur() {
      double res = 0;
      for (int ix = 0; ix < parking.length; ix++) {
         if (null != parking[ix]) {
            res += parking[ix].getPrixTTC();
         }
      }
      return res;
   }

   public String toString() {
      return Arrays.toString(parking);
   }

   public static void main(String[] args) {
      VoitureV3 maVoiture = new VoitureV3("123DG56", "verso", 11567.56, GRAY);
      VoitureAncienneV3 monAntiquité = new VoitureAncienneV3("345KL34", "datsun", 885, GRAY, 1945);
      VoitureAncienneV3 monAntiquité2 = new VoitureAncienneV3("346KL34", "datsun", 11567.56, GRAY, 1985);
      GarageB garage = new GarageB(5);
      garage.garer(maVoiture);
      garage.garer(monAntiquité);
      garage.garer(monAntiquité2);
      garage.retirer(monAntiquité);
      System.out.println(garage.getValeur());
      System.out.println("parking :" + garage);
      garage.retirer(monAntiquité2);
      System.out.println(garage.getValeur());
      System.out.println("parking :" + garage);

   }
}

Les modules et les conditions d’import/export

module com.maboite.monapp {
    requires java.desktop ;
    exports com.maboite.monapp.ihm;
}
module com.maboite.appclient {
    requires com.maboite.monapp;
}
module com.maboite.monapp {
    requires transitive java.desktop ;
    exports com.maboite.monapp.ihm;
}

Pour comprendre ce qui se passe.

Disons qu’un type qui est dans un module non importé (par requires ou transitivité) n’est pas en portée. Alors:

  • si une classe en portée hérite d’une classe qui n’est pas en portée on peut utiliser les méthodes héritées

  • si on accède à un objet d’une classe qui n’est pas en portée au travers d’un type en portée … c’est également bon. (à condition que cette classe soit "accessible" par le ClassLoader)

On en revient toujours aux problèmes de "responsabilité": la portée ne gère pas des "droits d’accès" au sens sécurité (un petit peu quand même quand nous verrons l’introspection).