Cette proposition de tutoriel n'attend que vos commentaires...
‘Typer ses variables selon l’interface’ : un pratique obligatoire en programmation orientée objet, pourtant délicate à mettre en œuvre en AS3 avec les classes qui étendent Sprite. Une solution élégante existe pourtant, et elle exploite une originalité de l’AS, les getters implicites.
Problématique
Rappel : programmer vers une interface
Programmer vers une interface, pas vers une implémentation : ce principe essentiel de la programmation objet s’applique en Actionscript comme dans d’autres langages.
Pour l’essentiel, cela signifie que chaque classe offre des méthodes publiques formalisées au travers d’une interface :
Action Script
public class MaClasse implements IMonInterface {
function maFonction (param1:Type):void {
//ici l'implémentation concrète de maFonction
};
}
Quant à l’interface, ses méthodes nécessairement publiques ne supportent, rappelons-le, aucun modificateur d’accès :
Action Script
public interface IMonInterface {
function maFonction (param:Type):void;
}
Selon les pratiques en vigueur, les classes clientes, qui instancient maClasse, doivent toujours typer la variable par l’interface :
Action Script
private instance:IMonInterface = new MaClasse();
et non
Action Script
private instance:MaClasse = new MaClasse();
On peut ensuite invoquer maFonction sur instance, mais seulement parce que maFonction est une méthode répertoriée dans IMonInterface..
Action Script
instance.maFonction(param);
Si ma fonction n’était qu’une méthode de MaClasse, quand bien même elle serait dotée du modificateur d’accès ‘public’, elle ne pourrait être appelée sur ‘instance’ : lors de la vérification des types à la compilation, ‘instance’ n’est pas considérée comme une MaClasse mais comme une IMonInterface.
Un principe qui élève le niveau de programmation
C’est ce principe qui garantit la qualité du code, en évitant de tirer des liaisons d’une classe vers l’implémentation d’une autre, ce qui débouche sur le fameux « code spaghetti ». A la longue, le respect de cette règle - qui peut sembler fastidieuse au débutant - permet un développement beaucoup plus rigoureux tout en favorisant la réutilisabilité du code. Tout bien considéré, cette pratique n’alourdit pas le travail du développeur. Dans un environnement de programmation de type Eclipse, si j’appelle sur mon instance une méthode qui n’existe pas encore - mais que j’ai l’intention de créer :
Action Script
instance.maDeuxiemeFonction(param);
L’éditeur me proposera aussitôt de la créer dans IMonInterface. Cela génèrera une erreur dans MaClasse puisqu’elle implémente IMonInterface et il suffira de valider « add unimplemented method » pour générer le squelette de la méthode avec la signature qui convient.
La difficulté en AS3 : les classes qui héritent d'une classe graphique
Toutefois, ce principe peut sembler ardu à mettre en oeuvre en actionscript 3. En effet, par nécessité, beaucoup de classes AS3 héritent d’une classe graphique – flash.display.Sprite le plus souvent.
Action Script
public class MaClasse extends sprite implements IMonInterface {
function maFonction (param1:Type):void ;
}
On va supposer qu’on a toujours l’interface suivante :
Action Script
public interface IMonInterface {
function maFonction (param:Type):void;
}
Dès lors, admettons que je type benoîtement l’instance selon l’interface pour me conformer aux standards de la POO : comme précédemment,
Action Script
private instance:IMonInterface = new MaClasse();
Le problème est que, dès lors, je ne serai plus en mesure de manipuler ‘instance’ en tant que Sprite !
Le code suivant génèrera une erreur à la compilation :
Action Script
addChild(instance);
Ou encore :
Action Script
instance.x = 50;
La variable instance est typée comme un IMonInterface, pas comme un sprite... Est-il dés lors possible de respecter le célèbre principe «Program to an interface not an implementation » ?
Solution
Deus ex machina : la méthode 'sprite'
Ce problème est résolu en ajoutant à l’interface la méthode ‘sprite’ -on va voir ici un intérêt des getters implicites qui constituent une sympathique originalité d’actionscript. Même ceux qui rechignent en temps normal à les utiliser vont devoir convenir qu’ils autorisent dans le cas présent une écriture fluide et intuitive. En outre, cette astuce va nous épargner d’avoir à multiplier les transtypages.
Ajoutons à notre interface cette simple déclaration :
Action Script
function get sprite(): Sprite;
Toute la beauté de l’implémentation dans la classe réside dans sa simplicité :
Action Script
public function get sprite ():Sprite { return this; }
Conclusion
Dès lors, la démarche qui semble devoir s’imposer en AS3 est la suivante :
- Déclarer la méthode sprite (ou shape, movieClip... et pourquoi pas displayObject, displayObjectContainer) dans toute interface susceptible d’être implémentée par des classes qui participent à la liste d’affichage.
- Implémenter la méthode sprite avec son instruction simplissime :
Action Script
return this;
- pour manipuler les instances en tant que sprite, le code suivant suffit :
Action Script
addChild(instance.sprite);
Ou encore :
Action Script
instance.sprite.x = 50;
Factorisons un peu...
Si ce principe doit être généralisé, il ne reste plus qu’à écrire une interface générale déclarant la méthode sprite :
Action Script
package monPackage {
import flash.display.Sprite;
public interface IAffichable {
function get sprite(): Sprite;
}
}
Dès lors, toutes les interfaces concernées hériteront de IAffichable :
Action Script
package monPackage {
public interface IMonInterface extends IAffichable {
//etc.
}
}
Peu à peu, cette façon d’appeler sprite sur les instances lorsqu’elles sont manipulées en tant qu’héritières de Sprite devient un automatisme.
En savoir plus
* Pas de lien particulier dans l'immédiat
