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 :

instanceof ou mauvais polymorphisme ? [Débat]


Sujet :

Langage Java

  1. #1
    Membre émérite Avatar de Djakisback
    Profil pro
    Inscrit en
    Février 2005
    Messages
    2 021
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2005
    Messages : 2 021
    Points : 2 278
    Points
    2 278
    Par défaut instanceof ou mauvais polymorphisme ?
    Salut, j'ai un problème de base mais je ne comprends pas très bien le mécanisme à adopter, si quelqu'un pouvait me guider. J'ai par exemple, 3 classes :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    public class SolidCircle extends Solid {
    	public boolean collideWith(SolidCircle circle) {...}
    }
     
    public class SolidRectangle extends Solid {
    	public boolean collideWith(SolidRectangle circle) {...}
    }
    Comment on fait pour récupérer et appeler la fonction adéquate dans le cas suivant, j'ai donc un vecteur qui contient des SolidRectangle et des SolidCircle :

    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
    public Vector movableSolids; // D'ailleurs il me semblait que Vector était pas trop optimisé pourtant c'est la seule structure que propose le CLDC 1.1 du J2ME
     
    static public void computeCollisions() {
    		for (int i = 0, solidsSize = PEngine.movableSolids.size(); i < solidsSize; i++) {
    			Solid solid1 = ((Solid) (PEngine.movableSolids.elementAt(i)));
    			for (int j = i + 1, solidsSize2 = PEngine.movableSolids.size(); j < solidsSize2; j++) {
    				Solid solid2 = ((Solid) (PEngine.movableSolids.elementAt(j)));
    				if (solid1.collideWith(solid2)) {
    					PEngine.computeCollisionResponse(solid1, solid2);
    				}
    			}
    		}
    	}
     
    	static public void computeCollisionResponse(SolidCircle circle1, SolidCircle circle2) {..}
     
    	static public void computeCollisionResponse(SolidRectangle rectangle1, SolidRectangle rectangle2) {...}
    J'ai pensé définir une méthode abstraite collideWith(Solid s) dans Solid mais ensuite il faut que j'en implémente une aussi dans SolidRectange et dans SolidCircle, ce qui n'a aucune utilité. Ma question est donc, comment appeler les bonnes méthodes collideWith et computeCollisionResponse, en fonction des types réels des instances, j'imagine qu'il y a moyen de faire ca sans instanceof ?
    Merci d'avance ^^
    Vive les roues en pierre

  2. #2
    Membre expérimenté Avatar de willoi
    Profil pro
    Développeur informatique
    Inscrit en
    Décembre 2006
    Messages
    1 355
    Détails du profil
    Informations personnelles :
    Âge : 51
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Décembre 2006
    Messages : 1 355
    Points : 1 639
    Points
    1 639
    Par défaut
    A mon avis cette ligne :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    PEngine.computeCollisionResponse(solid1, solid2);
    doit te donner une erreur de compilation.Car tu passe les parametres Solid, Solid a ta methode et celle ci n'existe pas.

    Donc une solution peut etre d'utiliser instanceof puis un casting a la classe adequate.

    Ou sinon implementer des methodes au niveau de tes classes SolidRectangle et SolidCircle.
    Exemple :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    solid1.computeCollisionResponse(solid2);
    et creer une methode dans ta classe Solid :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    computeCollisionResponse(Solid solid);

  3. #3
    Membre du Club
    Inscrit en
    Juillet 2006
    Messages
    113
    Détails du profil
    Informations forums :
    Inscription : Juillet 2006
    Messages : 113
    Points : 65
    Points
    65
    Par défaut
    à mon avis tu ajoute ces deux method dans tes class, et comme ça seulon le type des parametre java va savoire quel méthod utiliser.


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    public class SolidCircle extends Solid {
    	public boolean collideWith(SolidCircle circle) {...}
            public boolean collideWith(SolidRectangle rectangle) {...}
    }
     
    public class SolidRectangle extends Solid {
    	public boolean collideWith(SolidRectangle rectangle) {...}
            public boolean collideWith(SolidCircle circle) {...}
    }
    et aussi dans l'autre classe il faut ajouter les deux methodes:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    static public void computeCollisionResponse(SolidCircle circle, SolidCircle rectangle) {..}
    static public void computeCollisionResponse(SolidRectangle rectangle,  SolidCircle circle) {...}
    ou à mon avis je dit de n'importe quoi. pour ce deusiéme probléme il faut peut etre faire comme ce qu' à dit "willoi"

    en tous cas, tu doit développer deux methodes
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    computeCollisionResponse(Solid solid);
    dans chaque class (circle et rectangle)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    public class SolidCircle extends Solid {
    	computeCollisionResponse(SolidCircle circle){...}
            computeCollisionResponse(SolidRectangle rectangle){...}
    }
     
    public class SolidRectangle extends Solid {
    	computeCollisionResponse(SolidCircle circle){...}
            computeCollisionResponse(SolidRectangle rectangle){...}
    }

  4. #4
    Membre confirmé
    Inscrit en
    Mai 2007
    Messages
    335
    Détails du profil
    Informations forums :
    Inscription : Mai 2007
    Messages : 335
    Points : 511
    Points
    511
    Par défaut
    Bonjour,
    je vois bien une solution simple:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    public abstract class Solid {
    	public final boolean collideWith(Solid solid) {
                 if (solid instanceof SolidCircle) return collideWith((SolidCircle) solid);
                 if (solid instanceof SolidRectangle) return collideWith((SolidRectangle) solid);
                return false;
            }
     
      protected abstract boolean collideWith(SolidCircle circle);
      protected abstract boolean collideWith(SolidRectangle rectangle);
    }
    parce que le polymorphisme ne s'applique pas sur la surcharge: il y aurais peut-être un moyen de faire du vrai polymorphisme en extrayant des méthodes dans des stratégies ou des Visitor, mais ça deviendrais over-compliqué.

  5. #5
    Membre confirmé
    Profil pro
    Inscrit en
    Janvier 2006
    Messages
    365
    Détails du profil
    Informations personnelles :
    Localisation : Maroc

    Informations forums :
    Inscription : Janvier 2006
    Messages : 365
    Points : 495
    Points
    495
    Par défaut
    Bonjour,
    Moi je préférerais plutôt ceci :
    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
     
    public abstract class Solid {
        public abstract boolean collideWith(Solid solid);
    }
     
    public class SolidCircle extends Solid {
        public boolean collideWith(Solid solid) {
             if (! solid instanceof SolidCircle)
                   return false;
     
            // sinon faire le traitement spécifique aux objets SolidCircle
           // et retourner "true" ou "false" selon le résultat du traitement
           SolidCircle circle = (SolidCircle)solid;
            ...
        }
    }
     
    public class SolidRectangle extends Solid {
        public boolean collideWith(Solid solid) {
             if (! solid instanceof SolidRectangle)
                   return false;
     
            // sinon faire le traitement spécifique aux objets SolidRectangle
           // et retourner "true" ou "false" selon le résultat du traitement
           SolidRectangle rect = (SolidRectangle)solid;
            ...
        }
    }
    Ceci a l'avantage de conserver le caractère polymorphique de la méthode collideWith() et permet d'ajouter de nouvelle sous-classes de la classe Solid sans affecter cette dernière.
    SCJP 5 / SCBCD 1.3 Certified

  6. #6
    Membre confirmé
    Inscrit en
    Mai 2007
    Messages
    335
    Détails du profil
    Informations forums :
    Inscription : Mai 2007
    Messages : 335
    Points : 511
    Points
    511
    Par défaut
    C'est vrai qu'on est obligé de modifier la classe abstraite pour chaque classe ajoutée, mais tu oublie un point
    ce code est faux:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
        public boolean collideWith(Solid solid) {
             if (! solid instanceof SolidRectangle)
                   return false;
    car un rectangle peut être en collision avec un cercle, et de même si on ajoute un SolidTriangle, il faudra revoir les classes cercle et rectangle pour gérer les collisions Triangle-cercle et triangle-rectangle.

    pour bien faire il faudrait des instance d'opérateur binaire isCollision(Solid,Solid) , surchargés pour chaque type de couple Solid-Solid (un peu comme un Comparator), ce qui trop compliqué pour un cas simple comme celui-ci.

  7. #7
    Membre confirmé
    Profil pro
    Inscrit en
    Janvier 2006
    Messages
    365
    Détails du profil
    Informations personnelles :
    Localisation : Maroc

    Informations forums :
    Inscription : Janvier 2006
    Messages : 365
    Points : 495
    Points
    495
    Par défaut
    Citation Envoyé par deltree
    C'est vrai qu'on est obligé de modifier la classe abstraite pour chaque classe ajoutée, mais tu oublie un point
    ce code est faux:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
        public boolean collideWith(Solid solid) {
             if (! solid instanceof SolidRectangle)
                   return false;
    car un rectangle peut être en collision avec un cercle, et de même si on ajoute un SolidTriangle, il faudra revoir les classes cercle et rectangle pour gérer les collisions Triangle-cercle et triangle-rectangle.

    pour bien faire il faudrait des instance d'opérateur binaire isCollision(Solid,Solid) , surchargés pour chaque type de couple Solid-Solid (un peu comme un Comparator), ce qui trop compliqué pour un cas simple comme celui-ci.
    Pourant à bien lire son premier post, il cherche plutôt à comparer des SolidCircle entre eux, des SolidRectangle entre eux, et ainsi de suite. Pour pouvoir appeler la méthode computeCollisionResponse() par exemple, les deux solid doivent être de même sous-classe. Ce qui suppose qu'il ne considère que les collisions d'objets de même type. Sinon il faudrait reconsidérer la notion de collision entre objets Solid, quel que soit le sous-type et dans ce cas il faudrait peut-être introduire une variable membre dans la classe Solid (rectangleShape par exemple) qui serait partagée par toutes les sous-classes et définirait donc ce qu'est une collision entre un cercle et un rectangle.
    Tout est question de définition des concepts.
    SCJP 5 / SCBCD 1.3 Certified

  8. #8
    Membre confirmé
    Inscrit en
    Mai 2007
    Messages
    335
    Détails du profil
    Informations forums :
    Inscription : Mai 2007
    Messages : 335
    Points : 511
    Points
    511
    Par défaut
    D'accord, moi je l'avais interprété comme étant de la collision d'objets géométrique
    de toutes façon, nos méthodes se rejoignent sur le fait qu'il faut appeler les objets par une seule méthode d'entrée publique "collideWith(Solid)" que tu implémente dans les sous classes pour plus d'évolutivité, et que moi je préfère implémenter dans la superclasse pour mieux "vérouiller" le code si jamais toutes les classes sont interdépendantes. Ce qui nous oblige à utiliser le instanceOf: dans les 2 cas, on est obligé.

  9. #9
    Membre émérite Avatar de Djakisback
    Profil pro
    Inscrit en
    Février 2005
    Messages
    2 021
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2005
    Messages : 2 021
    Points : 2 278
    Points
    2 278
    Par défaut
    Salut,
    et merci beaucoup pour vos réponses
    Mon but est en effet de pouvoir tester toutes les combinaisons possibles.
    J'aimerais vraiment éviter d'utiliser instanceof si c'est possible car ca me semble un peu lourd.
    Pour le collideWith je crois je vais finalement passer par une méthode de la classe statique PEngine, ca m'évitera des doublons de code, ca pourrait donner un truc du style :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    --- PEngine ----
    static boolean areCollide(SolidCircle s1, SolidCircle s2)
    static boolean areCollide(SolidRectangle s1, SolidRectangle s2)
    static boolean areCollide(SolidCircle s1, SolidRectangle s2)
    Mais finalement mon gros problème se situe à la récupération des objets depuis les listes. Je me demande si il vaudrait mieux pas que je sépare tout simplement les formes :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    static Vector movableSolidCircles;
    static Vector movableSolidsRectangles;
    static Vector movableSolidsPolygons;
    Comme ca je serai sûr des types réels à la récupération. Par contre ca risque de compliquer les boucles de parcours mais je pense que ca sera toujours mieux que des instanceof.

    En tout cas merci encore pour vos avis et suggestions ^^ (passés et futurs ;P)
    Vive les roues en pierre

  10. #10
    Membre confirmé
    Inscrit en
    Mai 2007
    Messages
    335
    Détails du profil
    Informations forums :
    Inscription : Mai 2007
    Messages : 335
    Points : 511
    Points
    511
    Par défaut Djakisback ... is back :D
    C'est une bonne idée en terme de conception de vouloir éviter l'instanceOf, et bien souvent ça montre que le polymorphisme est mal employé, en particulier quand le "message" i.e. la méthode s'adresse à un seul objet polymorphe.

    idée de départ de polymorphisme
    là on a 2 objets polymorphe, et c'est le drame, on atteind la limite du polymorphisme Java, et comme je tentait de l'évoquer, on pourrait tenter de passer outre en Définissant un type supplémentaire sous classé pour chaque couple de sous-classe de Solid-Solid:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    interface Collision{
    public boolean isCollided(Solid s1, Solid s2);
    }
    Cette classe définissant la collision vue comme un opérateur binaire de l'ensemble des Solid (edit: je me suis un peu emballé)

    C'est un sujet intéressant au niveau conceptuel, même si au niveau réalisation c'est carrément overkill( surtout si tu est en JME comme j'au cru comprendre)

    ta solution basée sur du static, ou alors sur la super classe
    Pour ce qui est de l'utilisation des static, pour moi la programmation objet doit toujours être logique, et donc dans notre cas l'objet doit pouvoir porter ses méthodes, quitte à rediriger sur des classes "utilitaires" constituées de méthodes statiques.
    Autre solution: tu ne duplique rien si tu met tout ton code dans la classe abstraite (mais on se demande alors l'utilité de sous-classer)

    Conception et implémentation d'un polymorphisme "binaire" sans instanceOf
    pour revenir au cas d'école de sous classement de Collision, j'improvise à l'instant ma solution:
    Dans une Factory destinée à instancier les Solid, on peut également instancier toutes les possibilités de Collision, et les affecter à 2 tableau collisionCandidates1 et collisionCandidates2 communs à tous les objets Solid d'un type... tout ça dans le seul but d'exploiter le polymorphisme de l'objet Solid sur 2 méthodes polymorphe me rendant les opérateurs binaires possibles (les Candidate) pourquoi 2?
    pour ensuite extraire l'intersection des 2 ensembles, et ne retenir que l'opérateur binaire possible. C'est un peu long, mais on n'a utilisé aucune instanceOf, et je ne vois pas plus imple pour l'instant. A défaut d'antériorité sur l'algo, appelons ça le "Deltree Overkill Binary Candidate Pattern" et voici le code

    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
     
    //passons nous de la Factory pour l'instant
    class RectRectCollision implements Collision{...}
    class RectCircleCollision implements Collision{...}
    class CircleRectCollision implements Collision{...}
    class CircleCircleCollision implements Collision{...}
     
    class Solid{
    // les collisions dont le 1er arguement est de mon type
    protected abstract void getCollisionCandidates1();
    // les collisions dont le  2ème argument est de mon type
    protected abstract voièmed getCollisionCandidates2();
     
    public boolean isCollided(Solid s2){
      return getCollision(this,s2).isCollided(this,s2);
    }
     
    // simplement renvoie les élements appartenant aux 2 listes
    private boolean listIntersection(List l1, List l2){
      // boucler sur l1
      for (int i ....){
        if l2.contains(l1.get(i))
    	 return l1.get(i)
      }
     
    }
     
    public Collision getCollision(){
      return listIntersection(s1.getCollisionCandidates1(), s2.getCollisionCandidates2() );
    }
    }
     
    public SolidCircle extends Solid{
      public static final List candidates1 = new ArrayList(new Object[]{
       new CircleCircleCollision(),
       new CircleRectCollision()});
      public static final List candidates2 = new ArrayList(new Object[]{
       new CircleCircleCollision(),
       new RectCircleCollision()});
      // le polymorphisme enfin !!
      getCollisionCandidates1(){ return candidates1;
     }
      getCollisionCandidates2(){ return candidates2;
     }
    }
    j'avoue que je me suis un peu amusé, à l'occasion, je testerait ça sur d'autre type d'opérateur binaire, avec notamment la gestion de commutativité.

  11. #11
    Membre confirmé
    Profil pro
    Inscrit en
    Janvier 2006
    Messages
    365
    Détails du profil
    Informations personnelles :
    Localisation : Maroc

    Informations forums :
    Inscription : Janvier 2006
    Messages : 365
    Points : 495
    Points
    495
    Par défaut
    Moi je n'ai toujours pas compris cette notion de collision, comment cela se traduit-elle ? Par exemple, qu'est-ce qui doit être vérifié pour conclure qu'un solidCircle est en collision avec un solidRectangle ? Il doit certainement y en avoir des variables membre qui sont comparées, mais lesquelles ?
    SCJP 5 / SCBCD 1.3 Certified

  12. #12
    Membre confirmé
    Inscrit en
    Mai 2007
    Messages
    335
    Détails du profil
    Informations forums :
    Inscription : Mai 2007
    Messages : 335
    Points : 511
    Points
    511
    Par défaut
    Les collisions c'est la gestion des objets dans un jeu 3D par exemple: 2 objet ne peuvent pas se trouver au même endroit sinon ils sont en collision: si c'est un mur on n'avance plus etc.

    géométriquement ça se traduit par le fait que 2 objets sont en collision s'il existe un point (x,y) qui appartient aux 2 figures géométriques (ou (x,y,z) en 3D ). Dans la pratique, l'algo va rechercher l'intersection entre les figures gémétrique.

  13. #13
    Membre émérite Avatar de Djakisback
    Profil pro
    Inscrit en
    Février 2005
    Messages
    2 021
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2005
    Messages : 2 021
    Points : 2 278
    Points
    2 278
    Par défaut
    Effectivement, l'idée du DOBCP est intéressante
    Vive les roues en pierre

  14. #14
    Membre confirmé
    Inscrit en
    Mai 2007
    Messages
    335
    Détails du profil
    Informations forums :
    Inscription : Mai 2007
    Messages : 335
    Points : 511
    Points
    511
    Par défaut

    ouaip, à défaut, un pattern BCP si ça fait un peu mégalo le nom de pseudo dans un pattern.

    as-tu essayé? ou est-ce que finalement tu n'avais pas besoin des instanceOf avec des méthodes static?

  15. #15
    Rédacteur
    Avatar de bulbo
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Février 2004
    Messages
    1 259
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 51
    Localisation : France

    Informations professionnelles :
    Activité : Consultant informatique
    Secteur : Finance

    Informations forums :
    Inscription : Février 2004
    Messages : 1 259
    Points : 1 937
    Points
    1 937
    Par défaut
    Pourquoi ne pas essayer une approche du type Visitor comme mentionne plus haut ?
    Ca parait la solution adequate, exemple avec du code:
    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
     
    public abstract class Solid
    {
     
      private String _name;
     
      /** Creates a new instance of Solid */
      public Solid(String aName)
      {
        _name = aName;
      }
     
      public abstract boolean collideWith(Solid aSolid);
     
      public boolean collideWith(SolidCircle aSolid)
      {
        return false;
      }
     
      public boolean collideWith(SolidRectangle aSolid)
      {
        return false;
      }
     
      public String toString()
      {
        return _name;
      }
     
      public static void main(String args[])
      {
        try
        {
          Solid a = new SolidCircle("A");
          Solid b = new SolidRectangle("B");
     
          a.collideWith(b);
          b.collideWith(a);
          b.collideWith(b);
        }
        catch (Exception e)
        {
          e.printStackTrace();
        }
      }
    }
    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
     
    public class SolidCircle extends Solid
    {
     
      /** Creates a new instance of SolidCircle */
      public SolidCircle(String aName)
      {
        super(aName);
      }
     
      public boolean collideWith(Solid aSolid)
      {
        return aSolid.collideWith(this);
      }
     
      public boolean collideWith(SolidCircle aSolid)
      {
        return PEngine.computeCircleCircleCollision(this, aSolid);
      }
     
      public boolean collideWith(SolidRectangle aSolid)
      {
        return PEngine.computeCircleRectangleCollision(this, aSolid);
      }  
    }
    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
    public class SolidRectangle extends Solid
    {
     
      /** Creates a new instance of SolidRectangle */
      public SolidRectangle(String aName)
      {
        super(aName);
      }
     
      public boolean collideWith(Solid aSolid)
      {
        return aSolid.collideWith(this);
      }
     
      public boolean collideWith(SolidCircle aSolid)
      {
        return PEngine.computeCircleRectangleCollision(aSolid, this);
      }
     
      public boolean collideWith(SolidRectangle aSolid)
      {
        return PEngine.computeRectangleRectangleCollision(this, aSolid);
      }
     
    }
    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
    public class PEngine
    {
     
      public static boolean computeCircleCircleCollision(SolidCircle circle1, SolidCircle circle2)
      {
        System.out.println("Collision Circle " + circle1 + " with Circle " + circle2);
        return true;
      }
     
      public static boolean computeCircleRectangleCollision(SolidCircle circle, SolidRectangle rect)
      {
        System.out.println("Collision Circle " + circle + " with Rectangle " + rect);
        return true;
      }
     
      public static boolean computeRectangleRectangleCollision(SolidRectangle rect1, SolidRectangle rect2)
      {
        System.out.println("Collision Rectangle " + rect1 + " with Rectangle " + rect2);
        return true;
      }
     
    }
    Avec ce code pas besoin d'instanceOf, le seul overhead est de devoir implementer la methode abstraite collideWith (toujours le meme code de toute facon donc pas tres dur a faire)
    Et d'implementer les collideWith avec en signature les solides possible au niveau collision, pour l'exemple j'ai utilise une classe PEngine contenant en static le code des collisions (et pas besoin de 36 signatures pour 2 memes types comme tu peux le voir)

    Si une collision n'est pas implementee dans la classe collideWith retournera false.

    En cas d'ajout d'un solide une nouvelle methode collideWith doit etre ajoutee a Solid et un collideWith doit etre defini dans chaque classe pouvant entrer en collision avec le nouveau solide.

    C'est lourd mais c'est l'inconvenient du typage dynamique a la mode java, pas le choix.

    Bulbo
    [Java] [NetBeans] [CVS]
    La FAQ Java
    Merci de ne pas me poser de questions techniques par MP.

  16. #16
    Membre émérite Avatar de Djakisback
    Profil pro
    Inscrit en
    Février 2005
    Messages
    2 021
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2005
    Messages : 2 021
    Points : 2 278
    Points
    2 278
    Par défaut
    Salut,
    merci pour cette nouvelle réponse ^^

    deltree << non, j'ai pas tenté

    Finalement j'ai tout résolu en statique, ca m'a semblé le moins lourd et le plus maintenable, donc pas de Solid.collideWith mais plusieurs fonctions statiques dans PEngine. En cas d'ajout d'une classe de solide, seule PEngine est modifiée.
    Je suis passé par des interfaces étant donné que l'héritage multiple n'existe pas :/, car en réalité j'ai (Solid<-SolidRectangle; Solid<-MovableSolid<-MovableSolidRectangle). J'avais donc besoin d'une interface ISolidRectangle. J'ai donc des méthodes dans PEngine prenant en arguments des interfaces :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    static public boolean areCollide(ISolidRectangle solid1, ISolidRectangle solid2)
    static public boolean areCollide(ISolidRectangle solid1, ISolidCircle solid2)
    etc.
    Et les réponses de collision prenant en compte des types de solides. Les réponses ne sont pas les mêmes entre 2 MovableSolid et 2 Solid :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    	static public void computeCollisionResponse(MovableSolidRectangle rectangle1, MovableSolidRectangle rectangle2)
    	static public void computeCollisionResponse(MovableSolidRectangle rectangle1, SolidRectangle rectangle2)
    etc.
    J'ai oublié de préciser que ceci n'est possible qu'en stockant les objets dans des listes séparés :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    Vector movableSolidsRectangles;
    Vector movableSolidsCircles;
    Vector solidsRectangles;
    etc.
    Vive les roues en pierre

  17. #17
    Membre confirmé
    Inscrit en
    Mai 2007
    Messages
    335
    Détails du profil
    Informations forums :
    Inscription : Mai 2007
    Messages : 335
    Points : 511
    Points
    511
    Par défaut

    J'ai réfléchi pendant 1/4 heure pour comprendre comment ça marche, pourtant je connait le pattern Visitor, mais je butait sur la méthode collideWith implémentée dans chaque classe pour faire un appel à la méthode surchargée et typée.

    Bref, c'est un bon compromis simplicité/modularité.

    ça ne vaudrais pas le coup de faire un JSR (?) à Sun pour qu'on puisse utiliser dynamiquement une surcharge au lieu de laisser tous les développeur de la Terre se faire des noeuds aux cerveaux là-dessus?

  18. #18
    Membre émérite Avatar de Djakisback
    Profil pro
    Inscrit en
    Février 2005
    Messages
    2 021
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2005
    Messages : 2 021
    Points : 2 278
    Points
    2 278
    Par défaut
    bulbo, avec ce code j'aurai quand même le problème que j'avais au départ pour le parcours de boucle non ? à savoir que les bonnes méthodes ne seront pas appelées en fonction des types réels des instances, étant donné que je suis obligé de caster pour la récupération :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    static public void computeCollisions() {
    		for (int i = 0, solidsSize = PEngine.movableSolids.size(); i < solidsSize; i++) {
    			Solid solid1 = ((Solid) (PEngine.movableSolids.elementAt(i)));
    			for (int j = i + 1, solidsSize2 = PEngine.movableSolids.size(); j < solidsSize2; j++) {
    				Solid solid2 = ((Solid) (PEngine.movableSolids.elementAt(j)));
    				if (solid1.collideWith(solid2)) { // Ici, ce ne sera pas la bonne méthode appelée il me semble
    					PEngine.computeCollisionResponse(solid1, solid2);
    				}
    			}
    		}
    	}
    si oui où est l'intérêt ?
    (J'ai du louper un truc, je réexamine le code ^^)
    Vive les roues en pierre

  19. #19
    Rédacteur
    Avatar de bulbo
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Février 2004
    Messages
    1 259
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 51
    Localisation : France

    Informations professionnelles :
    Activité : Consultant informatique
    Secteur : Finance

    Informations forums :
    Inscription : Février 2004
    Messages : 1 259
    Points : 1 937
    Points
    1 937
    Par défaut
    Citation Envoyé par Djakisback
    bulbo, avec ce code j'aurai quand même le problème que j'avais au départ pour le parcours de boucle non ? à savoir que les bonnes méthodes ne seront pas appelées en fonction des types réels des instances, étant donné que je suis obligé de caster pour la récupération :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    static public void computeCollisions() {
    		for (int i = 0, solidsSize = PEngine.movableSolids.size(); i < solidsSize; i++) {
    			Solid solid1 = ((Solid) (PEngine.movableSolids.elementAt(i)));
    			for (int j = i + 1, solidsSize2 = PEngine.movableSolids.size(); j < solidsSize2; j++) {
    				Solid solid2 = ((Solid) (PEngine.movableSolids.elementAt(j)));
    				if (solid1.collideWith(solid2)) { // Ici, ce ne sera pas la bonne méthode appelée il me semble
    					PEngine.computeCollisionResponse(solid1, solid2);
    				}
    			}
    		}
    	}
    si oui où est l'intérêt ?
    (J'ai dû louper un truc, je réexamine le code ^^)
    Essaye le code tel quel, l'exemple est 'parlant' si je puis dire, regarde les tests qui doivent etre fait (sans cast ni instanceOf) et regarde ce qui est execute.

    C'est un poil plus d'implementation que ce que tu fais mais tu tires vraiment avantage de la liaison dynamique et pas besoin de listes separees.

    Bulbo
    [Java] [NetBeans] [CVS]
    La FAQ Java
    Merci de ne pas me poser de questions techniques par MP.

  20. #20
    Membre émérite Avatar de Djakisback
    Profil pro
    Inscrit en
    Février 2005
    Messages
    2 021
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2005
    Messages : 2 021
    Points : 2 278
    Points
    2 278
    Par défaut
    Effectivement j'avais vraiment lu à l'arrache
    Cette solution est très intéressante.
    Je vais réfléchir à ce que je vais faire (et peut-être tester les 2 soluces en termes de vitesse, ca ajoute quand même quelques pointeurs pour chaque instance d'objet, je suis pas un rapace mais bon ), merci encore ^^
    Vive les roues en pierre

Discussions similaires

  1. instanceof c'est mauvais?
    Par pongping dans le forum Langage
    Réponses: 33
    Dernier message: 20/05/2007, 20h39
  2. Mauvais indicateur de connection
    Par calvin dans le forum Hibernate
    Réponses: 15
    Dernier message: 24/05/2004, 13h03
  3. [Tomcat][JSP] Mauvais fonctionnement
    Par gandalf_le_blanc dans le forum Tomcat et TomEE
    Réponses: 47
    Dernier message: 26/04/2004, 14h07
  4. Mauvais noms de colonnes lors d'une requête
    Par nmathon dans le forum Bases de données
    Réponses: 2
    Dernier message: 09/04/2004, 08h27
  5. mauvais code
    Par moumou dans le forum Autres SGBD
    Réponses: 3
    Dernier message: 17/04/2003, 16h56

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