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:
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:
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 ^^
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:
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:
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é.