JeuWeb - Crée ton jeu par navigateur
Compass : East Oriented - Version imprimable

+- JeuWeb - Crée ton jeu par navigateur (https://jeuweb.org)
+-- Forum : Discussions, Aide, Ressources... (https://jeuweb.org/forumdisplay.php?fid=38)
+--- Forum : Programmation, infrastructure (https://jeuweb.org/forumdisplay.php?fid=51)
+--- Sujet : Compass : East Oriented (/showthread.php?tid=7165)

Pages : 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


RE: Compass : East Oriented - srm - 05-06-2015

J'ai simplifié j'avais la flemme de créer une interface Beggar qui ne me servait à rien pour mon exemple, mais bon je vais corriger :p


RE: Compass : East Oriented - Xenos - 05-06-2015

Ta méthode est de traviole: tu acceptes en entrée n'importe quel $object, donc ta méthode (son algorithme) doit être capable de traiter n'importe quel objet.
Si c'est un Beggar ou un Kid, elle est faite de travers car tu appelles une méthode dessus alors que le typage de $object est mixed, et le instanceof te dis juste qu'il est Beggar/Kid (pas de giveGold définit sur ces interfaces).

Ton problème ici n'est pas que tu as une méthode qui discrimine, en interne, les cas; ton problème est que tu acceptes en entrée n'importe quelle variable ($object est non typé) et que tu fais ensuite des appels de méthode dessus. C'est comme si tu m'avais présenté ce code:

interface Hero
{
public function askGold($object);
}

interface Beggar
{
public function meetHero(Hero $hero);
}

class Conan implements Hero
{
public askGold(Beggar $object)
{
$object->giveGold($this->gold/2);
}
}

class FrancoisdAssise implements Beggar
{
public function meetHero(Hero $hero)
{
$hero->askGold($this);
}
}

$conan = new Conan();
$francoisdAssise = new FrancoisdAssise();
$francoisdAssise->meetHero($conan);

D'ailleurs, fait le test sur Netbeans: si le instaceof est fait, Netbeans te propose l'auto-complétion des méthodes associées à cette interface. s'il n'est pas fait, il ne te propose rien.

Ce que j'essaie de te faire passer, c'est que le typehinting définit ce que la méthode accepte en entrée, alors que l'instanceof définit comment son algorithme interne traite cette entrée, et cette méthode de traitement ne doit pas transpirer hors de la classe.


RE: Compass : East Oriented - srm - 05-06-2015

J'ai en effet oublié giveGold Smile


interface Hero
{
public function askGold($object);
}

interface Beggar
{
public function meetHero(Hero $hero);
public function giveGold($gold);
}

class Conan implements Hero
{
public askGold($object)
{
if ($object instanceof Beggar) {
$object->giveGold($this->gold/2);
} else if ($object instanceof Kid) {
$object->giveGold($this->gold);
}
}
}

class FrancoisdAssise implements Beggar
{

public function meetHero(Hero $hero)
{
$hero->askGold($this);
}

}

$conan = new Conan();
$francoisdAssise = new FrancoisdAssise();
$francoisdAssise->meetHero($conan);

C'est mieux ? Tu vois le soucis que ça va avoir ?


RE: Compass : East Oriented - Xenos - 05-06-2015

Je croyais l'absence de giveGold volontaire (je la suppose présente dans Kid aussi). Note que si elle est définit dans chacun des interfaces, alors même si elle a la même signature, ce ne sera pas la même méthode (car pas la même interface). Si c'est censé être la même méthode (avec seulement des valeurs pour giveGold qui changent), il faut qu'elle se trouve dans une interface séparée. Après, ou bien on typehint askGold avec cette interface, ou bien on instanceof dans cette interface.


Non, quel problème est censé survenir, qui ne surviendrait pas dans ton autre méthode?


RE: Compass : East Oriented - srm - 05-06-2015

Je créer un nouveau Héro CalamityJane :

interface Hero
{
public function askGold($object);
}

interface Beggar
{
public function meetHero(Hero $hero);
public function giveGold($gold);
}

interface Kid
{
public function giveGold($gold);
}

class Conan implements Hero
{
public askGold($object)
{
if ($object instanceof Beggar) {
$object->giveGold($this->gold/2);
}

if ($object instanceof Kid) {
$object->giveGold($this->gold);
}
}
}

class FrancoisdAssise implements Beggar
{

public function meetHero(Hero $hero)
{
$hero->askGold($this);
}

}

$conan = new Conan();
$francoisdAssise = new FrancoisdAssise();
$francoisdAssise->meetHero($conan);

class CalamityJane implements Hero
{
public askGold($object)
{
if ($object instanceof Beggar) {
$object->giveGold(0);
}

if ($object instanceof Kid) {
$object->giveGold($this->gold/2);
}
}
}

$calamityJane = new CalamityJane();
$francoisdAssise = new FrancoisdAssise();
$francoisdAssise->meetHero($calamityJane);

Toujours d'accord ? Pas de soucis ?
Le code original sans CalamityJane était une librairie.
CalamityJane est dans notre projet.

On met à jour la librairie et Conan sait maintenant gérer les Femmes.

class Conan implements Hero
{
public askGold($object)
{
if ($object instanceof Beggar) {
$object->giveGold($this->gold/2);
}

if ($object instanceof Kid) {
$object->giveGold($this->gold);
}

if ($object instanceof Women) {
$object->giveGold($this->gold * 10);
}
}
}

Tout joyeux dans mon code je me mets à utiliser cette nouvelle feature ou j'en ai besoin :

$conan = new Conan();
$superWomen = new SuperWomen();
$superWomen->meetHero($conan);
Et la vie est belle.

Puis plusieurs mois après, j'ajoute un système qui permet à CalamityJane de rencontrer des femmes :

$calamityJane = new CalamityJane();
$superWomen = new SuperWomen();
$superWomen->meetHero($calamityJane);
Et bien là, ça ne fait pas du tout ce que j'attendais.
Je débug et je me rends vite compte pourquoi : j'ai oublié de rajouter l'instanceof Women dans CalamityJane.


RE: Compass : East Oriented - Xenos - 05-06-2015

Citation :Conan sait maintenant gérer les Femmes.

Tu continues à confondre ce que la méthode accepte, et ce qu'elle en fait. Conan accepte n'importe quel objet, c'est la signature de la méthode qui le dit. Donc Hero gère n'importe quel objet, Femmes incluses, et si Conan décide de donner son or aux Femmes, c'est sa décision propre, interne.

L'algorithme de Conan ne discriminait pas les Femme avant, dans la nouvelle version oui. C'est la doc de Conan qui te le dit. L'objet Conan, pour le monde extérieur, n'a pas changé: il accepte toujours les mêmes messages puisque les signatures sont identiques. C'est sa façon de réagir qui a changé (comme ta TV incassable: elle acceptait encore le message "casse-toi", mais elle l'ignorait), et ça, c'est la doc qui te le définit (la doc de Conan).


Dans tout code, la sémantique est importante: si c'est copié/collé, c'est deux choses indépendantes qui agissent indépendamment. CalamityJane et Conan partagent la même interface: leurs méthodes acceptent la même chose. Ils ne partagent pas la même implémentation: leur façon de traiter le message diffère. Si Conan gère les Femme, tant mieux pour lui, mais en aucun cas cela ne concerne CalamityJane: seule son interface l'intéresse.


Pour bien le voir, voici l'espace publique de la lib et du projet:
Code :
interface Hero
    public function askGold(mixed);
interface Beggar
    public function meetHero(Hero);
    public function giveGold(mixed);
interface Kid
    public function giveGold(mixed);
class Conan implements Hero
class FrancoisdAssise implements Beggar
class CalamityJane implements Hero

C'est cela qui compte. C'est ce "contre" quoi tu codes. La discrimination éventuelle faite dans chaque classe, on s'en fiche. Que Conan décide de "gérer les Femme", c'est à dire de leur envoyer de l'or, c'est la décision interne de la classe. Elle apparait dans la doc, pas dans la signature de la méthode (c'est la liberté de la méthode de faire telle ou telle action dans telle ou telle situation).


Donc, non le "problème" soulevé n'en est pas un car la méthode de Hero gère n'importe quel objet, mais chaque classe implémente cette gestion comme elle l'entend. C'est le fondement d'une interface.


Note: cet espace publique est très peu pollué; dans la 2nde méthode, l'espace publique, aka la liste des messages acceptés par chaque interface donc par chaque classe, explose vite.
Note2 : l'algo de Conan est étrange: si un objet est Beggar&Kid&Femme, il lui file 3x son or... Smile


RE: Compass : East Oriented - srm - 05-06-2015

Donc au final comment je fais pour savoir quel objet est capable de gérer un Hero ?
Je regarde la doc c'est ça ?


RE: Compass : East Oriented - srm - 05-06-2015

Le fondement d'une interface c'est de définir un contrat précis pas autre chose ^^


RE: Compass : East Oriented - Xenos - 05-06-2015

Oui, le fondement de l'interface, c'est de définir les messages auxquels les classes les implémentant répondent. Ce n'est nullement de définir comment l'algorithme interne de ces classes se déroule (sinon, chaque méthode de chaque classe aurait sa propre interface dédiée).

Reprends la définition de la doc PHP: "Object interfaces allow you to specifie which methods a class must implement, without having to define how these methods are handled.". Chaque classe est libre d'implémenter la méthode à sa manière, et d'appliquer sa logique propre dans cette méthode.

Si tu veux savoir qui est capable de gérer un Hero, tu regardes le typehinting des méthodes :
Code :
interface Hero
    public function askGold(mixed);
interface Beggar
    public function meetHero(Hero);
    public function giveGold(mixed);
interface Kid
    public function giveGold(mixed);
class Conan implements Hero
class FrancoisdAssise implements Beggar
class CalamityJane implements Hero

Donc, qui accepte un Hero en entrée? Hero::askGold(mixed) Beggar::meetHero(Hero) Beggar::giveGold(mixed) Kid::giveGold(mixed);. Toutes ces classes acceptent un Hero en entrée: tu leur passe un Hero, elles font un truc sans planter au niveau du langage. Quel algorithme elles utilisent pour traiter cette entrée? Ca, c'est pas donné dans la signature de la méthode, mais dans la documentation de cette méthode pour chaque classe.


RE: Compass : East Oriented - srm - 05-06-2015

C'est bien ce que je pointe du doigt.
askGold mixed, en gros tu peux même passer un int, tu passes ce que tu veux, donc tu ne sais pas comment travailler avec ton object. Puisque le réel but de askGold c'est pas de marcher avec n'importe quel objet, ça aurai pu être le cas mais pas ici.