Refactoring de la méthode Seek
Nous venons de créer une classe Seeker dans l’idée de pouvoir ensuite facilement créer des variations de celle-ci. En POO, des “variations de classes” sont souvent implémentées par le mécanisme d’héritage dans lequel des classes enfants vont étendre une classe parent.
De l’ensemble des méthodes implémentées pour notre classe Seeker, c’est ici la fonction seek
qui est responsable du Seek Behavior utilisé. Ce sont ultimement des variations de ce comportement précis que nous cherchons à créer. Naïvement, c’est donc l’ensemble de la fonction seek
qui serait successivement remplacée (override
) par nos futures classes enfant.
Actuellement, le comportement de suivi est donc implémenté en un seul gros bloc représenté par la méthode seek
. Si l’on y regarde bien, celle-ci a en réalité de multiples responsabilités.
On peut actuellement dériver son comportement en quatre étapes :
- Calcul de la vitesse désirée
- Calcul de la vitesse de changement de direction
- Mise à jour de la vitesse actuelle
- Mise à jour de la rotation du véhicule
Chacune de ces étapes représente une responsabilité différente, et il serait intéressant de pouvoir les modifier individuellement.
De façon à pouvoir étendre plus finement notre classe Seeker
et notamment son comportement de suivi, nous allons donc refactorer (changer l’expression sans changer le comportement) la méthode seek
.
Comme nous souhaitons pouvoir modifier ces quatre responsabilités indépendamment les une des autres, tout en minimisant la duplication de code, nous allons extraire ces quatres “blocs” de code de la fonction seek
pour les remplacer par des fonctions respectives.
L’idée est donc de passer de ceci :
class MyClass {
doEverything(){
// First, do something
/** Code that does something **/
// Then, do something else
/** Code that does something else **/
// Finally, do this last thing
/** Code that does this last thing **/
}
}
à ceci :
class MyClass {
doEverything(){
this.doSomething();
this.doSomethingElse();
this.doThisLastThing();
}
doSomething(){
/** Code that does something **/
}
doSomethingElse(){
/** Code that does something else **/
}
doThisLastThing(){
/** Code that does this last thing **/
}
}
Note Ce procédé est très courant en POO, et amène à créer plus de fonctions mais dont les responsabilités sont mieux découpées, chacune d’entre-elle se retrouvant alors plus courte et moins complexe. C’est le plus souvent considéré bonne pratique (ça ne doit pas non plus devenir une fin en soit, le but final reste la qualité et maintenabilité du code).
Suite à ce refactoring, notre classe Seeker devrait avoir une interface semblable à celle-ci :
interface ISeeker {
static VEC_REF: Phaser.Point;
static MAX_SPEED: number;
//...
constructor(game: Phaser.Game, posX: number, posY: number): ISeeker;
init(game: Phaser.Game): void;
seek(pTarget: Phaser.Sprite): void;
getDesiredVelocity(pTarget: Phaser.Sprite): Phaser.Point;
getSteeringForce(vecDesired: Phaser.Point): Phaser.Point;
setNewVelocity(newVelocity: Phaser.Point): void;
lookAhead(): void;
}