Salut,
C'est avec plaisir que je donne les quelques informations que j'ai.

Envoyé par
donkeyquote
En fait la methode Clone doit etre virtuelle parce que la factory doit "creer le bon objet".
C'est vrai, mais c'est un peu court.

Envoyé par
donkeyquote
Mais ce qui me fait chi*r c'est de ne pas pouvoir faire appel de la methode attack() en tant qu'element de type "DecoratorArc" une fois que j'ai fait a posteriori un "wrapper" de type "DecoratorUpgradable".
Ceci en revanche n'est pas vrai. Si tu conçoit bien ta fonction Clone, tu peux tout à fait faire cela. Heureusement, sinon, il n'y aurait aucun intérêt à utiliser la factory.
Voici des indices pour te mettre sur la piste : oublions la factory pour le moment et concentrons nous sur les décorateurs. Si tu construit un objet "archer" de la manière dont tu l'as proposé :
1 2 3 4 5
| WarElement * aWarElement2 = new WarElement(100, 15); // Points of life 100, Power 15
aWarElement2 = new DecoratorArc(*aWarElement2, 200, 100); //Points of life upgrade 200 / Power 60
aWarElement2 = new DecoratorUpgradable(*aWarElement2);
aWarElement2->lifeUp(0.2); //+20% life up
aWarElement2->powerUp(0.3); //+30% power up |
et qu'ensuite, tu fais appel à la fonction, par exemple
Tu t'attend à ce qu'il se produise la chose suivante :
-> la fonction int DecoratorUpgradable::getLife() est exécutée
-> elle appelle la fonction int DecoratorArc::getLife()
-> celle-ci appelle la fonction int WarElement::getLife() qui renvoie 100
-> DecoratorArc::getLife() n'ajoute rien au résultat et se contente de le renvoyer
-> DecoratorUpgradable::getLife() ajoute 30% au résultat et le renvoie
Je suppose que tu as bien compris que chaque fonction d'un décorateur que tu redéfinis est obligée d'appeler la fonction équivalent de l'objet de base.
Imaginons par exemple que le fait de posséder l'arc fasse perdre deux points de vie à tes unités (par exemple, pour représenter la force qu'elles dépensent à l'utiliser).
Si tu as définis ta fonction
int DecoratorUpgradable::getLife()
comme ceci :
1 2 3 4
| int DecoratorUpgradable::getLife()
{
return m_Base.m_Life*m_coefficientUpgrade;
} |
et que tu définis ta fonction
int DecoratorArc::getLife()
comme ceci :
1 2 3 4
| int DecoratorArc::getLife()
{
return m_Base.m_Life-2;
} |
et bien ton programme ne marchera pas : quand tu appelleras
, il se produira la chose suivante :
-> la fonction int DecoratorUpgradable::getLife() est exécutée
-> elle n'appelle la fonction int DecoratorArc::getLife() elle renvoie directement m_Base (c'est à dire 100) -2, (c'est à dire 98)
Ce n'est pas ce que tu veux, ce que tu veux, c'est définir tes fonctions comme ceci :
1 2 3 4
| int DecoratorUpgradable::getLife()
{
return m_Base.getLife()*m_coefficientUpgrade;
} |
et
1 2 3 4
| int DecoratorArc::getLife()
{
return m_m_Base.getLife()-2;
} |
Ainsi tu auras exactement le comportement voulu et
CODE]aWarElement2.getLife()[/CODE] te renverra bien 100*1.3-2 = 128.
Je suppose que tu as parfaitement bien compris ceci.
Et bien maintenant il ne te reste plus qu'à appliquer le même raisonnement à la fonction .
Une fois que ceci sera fait, c'est à dire une fois que le code suivant fonctionnera :
1 2 3 4 5 6 7 8 9 10 11 12
| ...
WarElement * aWarElement2 = new WarElement(100, 15); // Points of life 100, Power 15
aWarElement2 = new DecoratorArc(*aWarElement2, 200, 100); //Points of life upgrade 200 / Power 60
aWarElement2 = new DecoratorUpgradable(*aWarElement2);
aWarElement2->lifeUp(0.2); //+20% life up
aWarElement2->powerUp(0.3); //+30% power up
WarElement * aWarElement1 = aWarElement2.Clone();
std::cout<<"Points of life of aWarElement1 before attack " <<aWarElement1 ->getTotalPointsOfLife()<<std::endl;
aWarElement2->attack(aWarElement1 );
std::cout<<"Points of life of aWarElement1 after attack " <<aWarElement1 ->getTotalPointsOfLife()<<std::endl; |
Ce ne sera plus très dur d'introduire la Factory et de faire fonctionner le code que tu proposes plus haut.
Partager