IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Langage Java Discussion :

Listes et generics


Sujet :

Langage Java

  1. #1
    Membre confirmé
    Profil pro
    Inscrit en
    Mai 2006
    Messages
    147
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2006
    Messages : 147
    Par défaut Listes et generics
    Bonjour,

    Un correspondant me signale rencontrer le problème suivant avec mon code :

    Error: (85, 136) java: incompatible types: java.util.List<capture#1 of ? extends jamel.util.Agent> cannot be converted to java.util.List<jamel.models.util.Employer>
    La ligne de code qui pose problème est la suivante :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    final List<Employer> newList = (List<Employer>) this.getSimulation().getSector(sectorName).selectAll();
    Et voilà la déclaration de selectAll() :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    	 /**
             * Returns a list of all agents of this sector, in a random order.
             * 
             * @return a list of all agents of this sector.
             */
    	List<? extends Agent> selectAll();
    La difficulté semble venir du fait que Agent et Employer sont deux interfaces indépendantes.
    Pourtant, lorsque la liste renvoyée par selectAll() contient des objets qui étendent à la fois Agent et Employer, je n'ai aucun problème.

    Pourquoi mon correspondant rencontre-t-il, lui, dans les mêmes circonstances, ce problème ?
    Comment résoudre cette incompatibilité ?

  2. #2
    Modérateur

    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    12 585
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 585
    Par défaut
    Hello,

    Citation Envoyé par sepas Voir le message
    Pourtant, lorsque la liste renvoyée par selectAll() contient des objets qui étendent à la fois Agent et Employer, je n'ai aucun problème.
    Aucun problème, c'est vite dit : Java te fait un énorme warning sur cette ligne. Et il a bien raison. Quel intérêt d'utiliser les génériques si on ne vérifie pas la cohérence de type ?

    Citation Envoyé par sepas Voir le message
    Pourquoi mon correspondant rencontre-t-il, lui, dans les mêmes circonstances, ce problème ?
    Il a certainement configuré son environnement pour que les warnings soient considérés comme des erreurs. C'est ce que font les professionnels.

    Citation Envoyé par sepas Voir le message
    Comment résoudre cette incompatibilité ?
    Il y a plusieurs approches.

    La meilleure est de te demander pourquoi tu fais ça, qui cause un warning évident puisque ça ignore la cohérence de typage, et de réorganiser ton code pour ne faire que du typage cohérent ou bien encadré.

    La seconde est de mettre un suppresswarning sur cette ligne. Après tout il en faut de temps en temps, mais un professionel ne le ferait que dans les bonnes circonstances, c'est à dire pas sur cette ligne.

    La troisième est de convaincre ton correspondant de changer sa conf' pour que les warnings ne soient pas des erreurs.
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  3. #3
    Membre confirmé
    Profil pro
    Inscrit en
    Mai 2006
    Messages
    147
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2006
    Messages : 147
    Par défaut
    Citation Envoyé par thelvin Voir le message
    Aucun problème, c'est vite dit : Java te fait un énorme warning sur cette ligne.
    Ok, j'avais rajouté @SuppressWarnings("unchecked").
    Si je retire cette annotation, j'ai effectivement un warning :

    Type safety: Unchecked cast from List<capture#1-of ? extends Agent> to List<Employer>
    Mais comment traiter correctement ce warning ? L'objet Sector est construit pour pouvoir contenir tout type d'agents, pas nécessairement de type Employer.

  4. #4
    Modérateur

    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    12 585
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 585
    Par défaut
    Dans ce cas,

    - Employer devrait être un sous-type de Agent.

    - Soit
    -- tu prends une List<Agent> ou une List<? extends Agent> et tu travailles avec

    -- tu rends Sector ou sa méthode selectAll() générique pour pouvoir être réglé à renvoyer des Employer et pas juste des Agent. Là tu dis que ça renvoie des Employer. Bon ben comment tu lui as signalé que c'est ça qu'il doit renvoyer et pas un autre type d'agent ? C'est sur ce moyen-là qu'il faut faire jouer les génériques.
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  5. #5
    Membre confirmé
    Profil pro
    Inscrit en
    Mai 2006
    Messages
    147
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2006
    Messages : 147
    Par défaut
    Citation Envoyé par thelvin Voir le message
    Employer devrait être un sous-type de Agent.
    Ca ne semble pas poser de problème.

    Citation Envoyé par thelvin Voir le message
    tu prends une List<Agent> ou une List<? extends Agent> et tu travailles avec
    Là, je ne te suis pas : que veux-tu dire ?

    Citation Envoyé par thelvin Voir le message
    tu rends Sector ou sa méthode selectAll() générique pour pouvoir être réglé à renvoyer des Employer et pas juste des Agent. Là tu dis que ça renvoie des Employer. Bon ben comment tu lui as signalé que c'est ça qu'il doit renvoyer et pas un autre type d'agent ? C'est sur ce moyen-là qu'il faut faire jouer les génériques.
    Le constructeur de Sector reçoit en argument un doc XML qui contient tous ses paramètres, dont le nom de la classe des agents dont il va être peuplé.
    Donc quand le constructeur a fini son job, le type d'agent du secteur est fixé.
    Comment à partir de là je peut rendre selectAll() générique ?

  6. #6
    Modérateur

    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    12 585
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 585
    Par défaut
    Citation Envoyé par sepas Voir le message
    Là, je ne te suis pas : que veux-tu dire ?
    Il pourrait être possible de ne pas avoir besoin de savoir que tes objets sont des Employer, et que juste travailler avec des Agent suffise.
    Employer pourrait par exemple ne pas avoir de méthode publique supplémentaire par rapport à Agent, ou bien tu pourrais ne pas vraiment en avoir besoin.
    Il serait possible aussi que, si tu as bel et bien besoin de ces méthodes, en réalité elles pourraient marcher en les mettant dans Agent, ou bien Agent pourrait être rendue plus générique de sorte que quelque chose de ce genre soit possible.

    Ça pourrait être possible.
    Mais... Peut-être que ça ne l'est pas, pas en faisant du typage simple et strict.
    Disons que ça pourrait être une solution. C'est à voir.
    Ce n'est pas forcément une solution.

    Citation Envoyé par sepas Voir le message
    Le constructeur de Sector reçoit en argument un doc XML qui contient tous ses paramètres, dont le nom de la classe des agents dont il va être peuplé.
    Donc quand le constructeur a fini son job, le type d'agent du secteur est fixé.
    Comment à partir de là je peut rendre selectAll() générique ?
    Bon ben, effectivement le Sector va décider lui-même quelle classe il produit, en fonction du contenu d'un fichier. Du coup la généricité ne peut pas être exprimée de ce côté-là.

    Mais au bout du compte, quand tu t'en sers, tu demandes à recevoir une List<Employer>. Donc tu sais à l'avance que ce Sector-là, il reçoit une configuration qui lui dit de renvoyer des instances de Employer.
    Ça veut dire qu'au moment de sa création, tu pourrais lui passer en paramètre la Employer.class pour lui signaler que c'est ça que tu attends qu'il produise, et qu'il vérifie que la conf' qu'il utilise respecte bien cela.

    Quelque chose de ce genre :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    public class Sector<E extends Agent> {
     
      public Sector(Document confFile, Class<E> agentClass) {
        readConf();
        checkThatConfProduces(agentClass);
      }
     
      public List<E> selectAll() {
        // ...
      }
     
    }
    qui serait construit ensuite avec :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Sector<Employer> employerSector = new Sector<>(confFile, Employer.class);
    Et derrière il faudrait le récupérer avec quelque chose comme :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    final List<Employer> newList = this.getSimulation().getEmployerSector(sectorName).selectAll();
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  7. #7
    Membre confirmé
    Profil pro
    Inscrit en
    Mai 2006
    Messages
    147
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2006
    Messages : 147
    Par défaut
    Je ne suis pas sûr que ce que tu proposes soit adapté à mon cas.

    Je m'explique. Actuellement, voilà comment marche mon code :

    Le nombre de secteurs, le choix du type d'agents qui peuplent les différents secteurs revient à l'utilisateur, qui spécifie ces types dans le fichier XML qui décrit son modèle.

    Mettons qu'il crée un modèle composé de deux secteurs :
    - un secteur qu'il nomme "firms" et qu'il choisit de peupler avec des agents de type Firm. Firm étend les interfaces Agent et Employer.
    - un secteur qu'il nomme "workers" et qu'il choisit de peupler avec des agents de type Household. Household étend les interfaces Agent et Worker.
    L'utilisateur spécifie aussi comment les agents des différents secteurs vont interagir.
    En particulier, l'utilisateur spécifie, dans les préférences des travailleurs, qu'ils doivent s'adresser au secteur "firms" pour chercher un employeur.

    Quand un travailleur est à la recherche d'un emploi, il s'adresse donc au secteur "firms", et lui demande une liste des agents qui le compose en appelant sa méthode selectAll().
    Sector.selectAll() renvoie une liste d'agents (List<Agent>).

    Le travailleur reçoit cette liste, et tente de la convertir en une liste d'employeurs (List<Employer>).
    Si l'utilisateur n'a pas fait d'erreurs dans la construction de son modèle, le cast réussit et le modèle peut tourner.
    Bien sûr, l'utilisateur peut avoir fait une erreur, par exemple en peuplant son secteur "firms" avec des agents qui n'étendent pas l'interface Employer.
    Mais cette erreur, qui réside dans le fichier XML spécifiant le modèle, ne peut être détectée qu'au moment de l'exécution du modèle, lorsqu'un travailleur tente de convertir la liste d'Agent reçu du secteur "firms" en une liste d'Employer.

    A ce moment là, l'exécution du modèle s'interrompt et l'utilisateur reçoit un message l'informant qu'il a mal spécifié son modèle, et que son secteur "firms" est peuplé d'agents qui ne peuvent remplir les fonctions d'employeur pour les agents du secteur des travailleurs.

    Quel est le problème de faire ainsi ? A partir du moment où la possibilité d'une incompatibilité de type peut apparaître à l'exécution, je ne vois pas comment utiliser correctement les generics ici, puisqu'ils sont (si j'ai bien compris) justement conçus pour prévenir ces incompatibilités dès la compilation.

    Tu ne crois pas ?

  8. #8
    Modérateur

    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    12 585
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 585
    Par défaut
    C'est ce que j'ai dit, là à la compilation ça ne va pas être possible.

    Mais les génériques ne limitent pas leur utilité à la compilation, c'est juste l'utilisation la plus simple.
    Ils servent à s'assurer qu'on est strictement typé, et à échouer le plus tôt possible quand le typage n'est pas assuré.

    Échouer à la compilation quand le typage n'est pas respecté, c'est l'idéal. Mais pas toujours possible. Ce n'est pas une raison pour se résigner à ce que les erreurs de typage arrivent à des endroits complètement imprédictibles parce qu'on pensait traiter une List de Employer pendant tout un process mais c'est seulement cinq couches plus tard qu'on fait vraiment de la réification et BAM en fait d'Employer on a un Salaryman et ClassCastException.

    Dans ce cas-là, ce qu'on veut, c'est échouer au moment où on croyait récupérer une List d'Employer mais il se trouve que c'est autre chose qu'on a à nous donner. Le non-respect du typage arrive là, donc c'est là qu'on veut une erreur. Pas plus tard, à un endroit où on croyait qu'on avait déjà notre Liste d'Employer.

    Vu ce que tu décris, ce que je proposais faisait de la détection d'erreur plus tôt qu'il n'est possible. Très bien, alors ne détectons pas aussi tôt, mais aussi tôt que possible.

    Quand tu appelles ton getSector(sectorName), tu sais que tu en veux un qui va donner des Employer quand tu fais selectAll(). Donc tu devrais faire un getEmployerSector(sectorName) à la place, qui renvoie un Sector<Employer> qui va te faire ça.

    Reste à faire en sorte que getEmployerSector(sectorName) vérifie que le Sector renvoyé est bien un Sector<Employer>. Le Sector, lorsqu'il a fini de lire sa conf', il sait quelle classe il fournit. Il peut donc garder cette information en interne dans une variable Class<E> agentClass.

    Du coup quand tu appelles getEmployerSector(sectorName) dans le but d'avoir ce Sector, la classe Simulation peut le trouver grâce à son sectorName, mais elle ne sait pas s'il fournit bien des Employer. Mais puisque lui le sait, elle peut tout simplement lui demander si c'est le cas. Et sinon, lancer une Exception qui indique que tu as demandé le Sector sectorName pour te fournir des Employer, mais il se trouve que le Sector de ce nom-là ne fournit pas cela.

    => ainsi est remontée l'erreur de typage aussi tôt qu'elle arrive.
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  9. #9
    Membre confirmé
    Profil pro
    Inscrit en
    Mai 2006
    Messages
    147
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2006
    Messages : 147
    Par défaut
    Citation Envoyé par thelvin Voir le message
    C'est ce que j'ai dit, là à la compilation ça ne va pas être possible.
    Ok.

    Mais les génériques ne limitent pas leur utilité à la compilation, c'est juste l'utilisation la plus simple.
    Ils servent à s'assurer qu'on est strictement typé, et à échouer le plus tôt possible quand le typage n'est pas assuré.

    Échouer à la compilation quand le typage n'est pas respecté, c'est l'idéal. Mais pas toujours possible. Ce n'est pas une raison pour se résigner à ce que les erreurs de typage arrivent à des endroits complètement imprédictibles parce qu'on pensait traiter une List de Employer pendant tout un process mais c'est seulement cinq couches plus tard qu'on fait vraiment de la réification et BAM en fait d'Employer on a un Salaryman et ClassCastException.

    Dans ce cas-là, ce qu'on veut, c'est échouer au moment où on croyait récupérer une List d'Employer mais il se trouve que c'est autre chose qu'on a à nous donner. Le non-respect du typage arrive là, donc c'est là qu'on veut une erreur. Pas plus tard, à un endroit où on croyait qu'on avait déjà notre Liste d'Employer.
    J'admets.

    Vu ce que tu décris, ce que je proposais faisait de la détection d'erreur plus tôt qu'il n'est possible. Très bien, alors ne détectons pas aussi tôt, mais aussi tôt que possible.

    Quand tu appelles ton getSector(sectorName), tu sais que tu en veux un qui va donner des Employer quand tu fais selectAll().
    Tout à fait d'accord.

    Donc tu devrais faire un getEmployerSector(sectorName) à la place, qui renvoie un Sector<Employer> qui va te faire ça.
    Là, ça me paraît beaucoup plus difficile.
    On a un objet de type Simulation qui contient la liste de tous les secteurs (en fait, une HashMap<String,Sector>).
    Sector n'est qu'une interface, certains secteurs concrets pouvant être d'un type multi-agents, comme "firms" et "workers", d'autres pouvant être d'un type agrégé, le secteur représentant alors un seul acteur (un marché, l'Etat, la banque centrale, le reste du monde...).

    Lorsque le secteur des travailleurs est initialisé, chaque travailleur nouvellement créé reçoit, dans le doc XML qu'il a reçu en argument, le nom du secteur des employeurs (ici, "firms").
    A ce moment (si l'utilisateur a décrit les secteurs dans le bon ordre dans le fichier XML décrivant son modèle) le secteur des employeurs doit déjà être initialisé.
    Donc, en suivant ce que tu dis, c'est le moment de détecter si le secteur désigné est capable ou non de renvoyer une List<Employer>.

    Tout ce que peut faire le travailleur, c'est s'adresser à la simulation pour lui demander de lui renvoyer le secteur qui porte le nom "firms".
    Tout ce que peut faire la simulation, c'est renvoyer le secteur qu'elle trouve dans HashMap à ce nom et qui, pour elle, est de type Sector sans autre précision.

    Donc il ne peut y avoir, au niveau de la simulation, de méthode getEmployerSector(sectorName).
    C'est à chaque travailleur de vérifier si le secteur qu'on lui désigne comme employeur en est effectivement un, c'est-à-dire qu'il renvoie une List<Employer> quand on lui demande la liste de ses agents.

    Si je veux te suivre, il faut alors que getEmployerSector(sectorName) soit une méthode de Worker.

    Reste à faire en sorte que getEmployerSector(sectorName) vérifie que le Sector renvoyé est bien un Sector<Employer>. Le Sector, lorsqu'il a fini de lire sa conf', il sait quelle classe il fournit. Il peut donc garder cette information en interne dans une variable Class<E> agentClass.
    Jusqu'à présent je stockais cette information ainsi (dans l'objet BasicSector, implémentation multi-agent de l'interface Sector) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    	/**
             * The class of the agents that populate the sector.
             */
    	final private Class<? extends Agent> agentClass;
    Du coup quand tu appelles getEmployerSector(sectorName) dans le but d'avoir ce Sector, la classe Simulation peut le trouver grâce à son sectorName, mais elle ne sait pas s'il fournit bien des Employer. Mais puisque lui le sait, elle peut tout simplement lui demander si c'est le cas. Et sinon, lancer une Exception qui indique que tu as demandé le Sector sectorName pour te fournir des Employer, mais il se trouve que le Sector de ce nom-là ne fournit pas cela.
    Donc, dès que le travailleur connait le nom du secteur employeur :
    - il demande à la simulation ce secteur,
    - il demande au secteur quel est le type d'agent qui le peuple (je rajoute à l'interface Sector une méthode getAgentType()),
    - si le type retourné est incompatible avec Employer on lance une exception.
    Ainsi, comme tu dis, l'erreur est déclenchée le plus tôt possible, à l'initialisation du Worker, et non plus tard lorsque le travailleur commence le job search.

    Mais, quand bien même le secteur "firms" passe correctement ce chek, je vais rester avec le même warning au niveau du job search, quand le travailleur va demander au secteur "firms" de lui renvoyer la liste de ses agents et qu'il va vouloir la convertir en une liste d'employeurs.

  10. #10
    Modérateur

    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    12 585
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 585
    Par défaut
    Je ne comprends pas ce qui te fait penser que dans cette ligne :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    final List<Employer> newList = (List<Employer>) this.getSimulation().getSector(sectorName).selectAll();
    il n'est pas possible de remplacer getSector(sectorName) par getEmployerSector(sectorName). Tu me parles du fait que la Simulation ne peut pas savoir le type d'un sector avant qu'il soit construit.
    Bon, mais là on est après qu'il soit construit, pas avant, alors quelle importance ?

    Puisque la simulation est en charge de fournir le sector, il me semble qu'elle devrait aussi être en charge de vérifier que le sector qu'on lui demande de fournir va bien donner les éléments qu'on veut.

    Mais peut-être que ce n'est pas logique dans le domaine avec lequel tu travailles. Au bout d'un moment c'est ton programme, donc tu es mieux placé que moi pour savoir qui doit décider quoi à quel moment et quel endroit.

    Citation Envoyé par sepas Voir le message
    Mais, quand bien même le secteur "firms" passe correctement ce chek, je vais rester avec le même warning au niveau du job search, quand le travailleur va demander au secteur "firms" de lui renvoyer la liste de ses agents et qu'il va vouloir la convertir en une liste d'employeurs.
    Oui, tu auras un ou deux warnings, suivant la manière dont tu t'organises. C'est inévitable avec les architectures incapables de vérifier le typage à la compilation.

    Et pour éviter que ces warnings polluent le contrôle qualité de ton code, il leur faudra un SuppressWarning...
    Que tu pourras entièrement justifier du fait de leur nécessité, et que le contrôle statique qu'il fait ignorer, tu l'assures de manière dynamique à cet endroit même du code.

    On est loin du "bon et là on a un warning parce que la méthode donne List<? extends Agent> et qu'on veut List<Employer> à la place".

    Voici un exemple de ce que ça peut donner :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    public class Sector<E extends Agent> {
     
      private final Class<? extends E> agentClass;
      private final List<E> agents = new ArrayList<>();
     
      private Sector(Class<? extends E> agentClass) {
        this.agentClass = agentClass;
     
        try {
          for(int i = 0; i < 5; i++) {				
            agents.add(agentClass.newInstance());
          }
        } catch (InstantiationException|IllegalAccessException e) {
          throw new IllegalStateException(e.getMessage(), e);
        }
      }
     
      // When building Sectors we don't know what is their <E>, so we build them as Sector<?>
      static Sector<?> build(String agentClassName) {
        try {
          // ensure the class is subtype of Agent
          Class<? extends Agent> verifiedClass = Class.forName(agentClassName).asSubclass(Agent.class);
     
          // build as Sector<Agent> for now, let callers ask for a specialization
          return new Sector<Agent>(verifiedClass);
        } catch (ClassNotFoundException e) {
          throw new IllegalArgumentException(e.getMessage(), e);
        }
      }
     
      public List<E> selectAll() {
        return agents;
      }
     
      @SuppressWarnings("unchecked") // check is done dynamically
      public <T extends Agent> Sector<T> asProviding(Class<? extends T> agentClass) {
        if(!agentClass.isAssignableFrom(this.agentClass)) {
          throw new IllegalArgumentException("Required sector to provide " + agentClass + " but it provides " + this.agentClass);
        }
        return (Sector<T>)this;
      }
     
      public static void main(String[] args) {
        Map<String, Sector<?>> sectors = new HashMap<>();
        sectors.put("employers", Sector.build("sectors.Employer"));
     
        Sector<Employer> sector = sectors.get("employers").asProviding(Employer.class);
        for(Employer employer : sector.selectAll()) {
          System.out.println(employer);
        }
      }
     
    }
    Il y a bien un SuppressWarning, mais pas n'importe où !
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  11. #11
    Membre confirmé
    Profil pro
    Inscrit en
    Mai 2006
    Messages
    147
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2006
    Messages : 147
    Par défaut
    Simulation ne peut pas comporter de méthode getEmployerSector() parce que c'est un objet capable d'accueillir n'importe quel modèle, pas nécessairement comportant un secteur employeur.

    Ceci dit, j'ai compris, je crois, qu'il faut simplement accepter le fait pour le Worker de ne pas caster la liste qu'il reçoit en une liste d'Employer.
    Quand le travailleur va parcourir la liste pour rechercher un emploi, il castera un a un les agents qui composent la liste, pour avoir accès à la méthode getJobOffer() de Employer.
    Et c'est là qu'une exception sera lancée si la liste n'est pas constituée d'Employer.
    Si je fais ça, je n'aurai plus de warning (et mon correspondant n'aura plus d'erreurs).
    En revanche il faut que je fasse un try catch autour, pour pouvoir en cas d'échec du cast informer correctement l'utilisateur que l'erreur provient d'un paramétrage erroné du secteur employeur.

    Pour moi, c'est résolu, et je te remercie de ton aide.

  12. #12
    Modérateur

    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    12 585
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 585
    Par défaut
    Citation Envoyé par sepas Voir le message
    Simulation ne peut pas comporter de méthode getEmployerSector() parce que c'est un objet capable d'accueillir n'importe quel modèle, pas nécessairement comportant un secteur employeur.
    Quelle importance ?

    Ce qui est important c'est que certaines parties de ton programme vont avoir besoin de recevoir des Employer. Elle peut donc avoir cette méthode dans le but de leur fournir ce dont elles ont besoin.
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  13. #13
    Membre confirmé
    Profil pro
    Inscrit en
    Mai 2006
    Messages
    147
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2006
    Messages : 147
    Par défaut
    Citation Envoyé par thelvin Voir le message
    Quelle importance ?

    Ce qui est important c'est que certaines parties de ton programme vont avoir besoin de recevoir des Employer. Elle peut donc avoir cette méthode dans le but de leur fournir ce dont elles ont besoin.
    Non, Simulator n'est pas sensé connaître toutes les classes et les interfaces futures décrivant les agents: il doit juste connaitre l'interface Sector.

    L'utilisateur doit pouvoir se concentrer sur le développement de son modèle, c'est-à-dire définir lui-même ses propres rôles et agents ainsi que leurs interactions, sans avoir à redéfinir les objets de base, purement techniques et "non-économiques", que sont Simulator et Sector qui doivent être commun à tous les modèles, et par conséquent être minimalistes et polyvalents.

  14. #14
    Modérateur

    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    12 585
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 585
    Par défaut
    Je vois pas l'intérêt de pousser le découplage jusqu'à sa perfection théorique, un peu de code raccourci ne fait pas de mal tant qu'il s'appuie sur une architecture déjà découplée.

    Mais si c'est si important, tu peux facilement faire :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    public <T extends Agent> Sector<T> getSector(String name, Class<T> agentClass) {
      return getSector(name).asProviding(agentClass);
    }
    Ou juste, au niveau de l'appelant :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    final List<Employer> newList = this.getSimulation().getSector(sectorName).asProviding(Employer.class).selectAll();
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  15. #15
    Membre confirmé
    Profil pro
    Inscrit en
    Mai 2006
    Messages
    147
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2006
    Messages : 147
    Par défaut
    Ok, je vais y réfléchir.
    Je te remercie encore.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 4
    Dernier message: 06/11/2007, 21h05
  2. Stéréotype List et generics java
    Par ptit-lu dans le forum BOUML
    Réponses: 4
    Dernier message: 30/07/2007, 10h11
  3. [Generics] ajouter un élement dans une liste typée
    Par anitshka dans le forum Collection et Stream
    Réponses: 14
    Dernier message: 06/02/2007, 11h04
  4. [Generics][Tableaux][Collections] Tableau liste entiers
    Par MyGoddess dans le forum Collection et Stream
    Réponses: 4
    Dernier message: 04/11/2005, 12h44
  5. [generic] pb création d'une List []
    Par yoplaboom dans le forum Langage
    Réponses: 6
    Dernier message: 08/07/2005, 13h01

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo