Je vais reprendre pas à pas et expliquer ce que j'ai fait.
Déjà on va expliciter avec un diagramme :
Le bloc Expression est une interface et non une classe. Cela signifie que toute classe qui implémente Expression devra posséder une méthode calcul(). On fixe en fait un contrat de telle manière que l'on soit sûr que cette méthode existera dans toute classe qui se déclare être une Expression :
interface Expression
{
function calcul();
}
Les classes Valeur, Fois, et Plus (on peut en imaginer d'autres) sont des Expression.
La classe Valeur est une Expression assez simple, puisque sa seule donnée est un entier. Quand on va vouloir calculer la valeur de cette Expression, il suffira de retourner cet argument. C'est pourquoi la méthode calcul() est très simple :
class Valeur implements Expression
{
private $val;
function __construct(int $val)
{
$this->val = $val;
}
function calcul()
{
return $this->val;
}
}
Les classes Plus et Fois sont quasiment identiques (je ne décris que Plus). En fait, c'est là qu'arrive l'intérêt de la récursivité. Comment traiter les cas de 5 - (3 + 2 + 5) ou 8 * 9 * (3 + 1) ? Il y a des parenthèses à gérer. C'est là qu'on simplifie en revenant à la définition stricte d'une opération :
Une opération Plus (par exemple) prend deux Expression et les additionne. Cette opération étant elle-même une Expression. On applique simplement ce principe, notre opération Plus aura un attribut exp1 et un attribut exp2, tous deux des Expressions, et est elle-même une Expression (donc notre opération Plus va aussi implémenter la classe Expression).
Donc dans le cas où on a 5 + 6 + 8, notre première opération Plus aura pour arguments l'Expression 5 (représenté dans une classe Valeur), et l'Expression 6+8 (représenté dans une classe Plus).
Pour le calcul la récursivité est là aussi géniale. En fait, une fois que tu as ton Expression Plus composée de 5 et de 6+8, le résultat du calcul sera simplement le résultat du calcul de 5 ajouté au résultat du calcul de 6+8. L'objet Plus qui représentera 6+8 se chargera à son tour d'appeler le calcul de 6 et le calcul de 8 pour les additionner, et retourner le résultat à la méthode qui l'a appelé.
Ce qui donne :
class Plus implements Expression
{
private $exp1;
private $exp2;
function __construct(Expression $exp1, Expression $exp2)
{
$this->exp1 = $exp1;
$this->exp2 = $exp2;
}
function calcul()
{
return $this->exp1->calcul() + $this->exp2->calcul();
}
}
Pour les autres fonctions de calcul c'est exactement pareil. Après je ne dis pas que tu auras un truc forcément plus rapide, mais il faut que tu comprennes que cette approche est la meilleure. La Programmation Orientée Objet te permet de structurer tes programmes et de simplifier des opérations complexes.
Après c'est à toi de voir si tu l'appliques mais il faut absolument que tu comprennes cette solution pour élargir ta vision des choses. Si tu peux comprendre et réutiliser le principe de récursivité, tu feras un très grand pas dans l'informatique.
Voilà, n'hésite pas à poser d'autres questions.
