Forums Développement Multimédia

Les formations Mediabox
Les formations Mediabox
Compatible ActionScript 3. Cliquer pour en savoir plus sur les compatibilités.Par Nataly, le 16 juin 2010

Introduction
Classe de base (#1)
Classe de base (#2)
Héritage et surcharge (#1)
Héritage et surcharge (#2)
Diffuser des événements
Classe liée
Classe de document
Classe externe : une visionneuse (#1)
Classe externe : une visionneuse (#2)
Classe externe : méthodes statiques

Méthodes et propriétés statiques

Ça y est la balade touche à sa fin. On a vu le plus gros du primordial. Ne reste plus à traiter que le cas du mot clé attribut static, attaquons donc sans plus de préambule.

C'est un mot clé bien utile : il permet de spécifier qu'une méthode (variable ou constante) appartient à la classe, et non pas aux occurrences de la classe. C'est la doc qui le dit.
Présenté autrement : c'est utile quand on souhaite se fabriquer ce que j'ai appelé une classe outil en introduction. Une classe qu'on souhaite utiliser sans en créer d'instance, justement. J'avais pris pour exemple le volume d'un tonneau… Vous vous souvenez ?

Méthode statique

Une méthode statique, donc, est appelée directement depuis la classe sans nécessité d'en créer une instance.
On peut prendre pour exemple, une classe native fréquemment utilisée que vous connaissez sûrement : la classe Math. Elle met à notre disposition une quantité de méthodes, toutes statiques (cos, floor, max…). C'est clairement lisible dans leur signature. Prenons la méthode cos, :

public static function cos(angleRadians:Number):Number

Je vous propose, à titre d'exemple, une classe générique de traitement des dates que vous pourrez fort bien ranger dans le répertoire Mezoutils (du moins l'équivalent chez vous)

La classe Date native nous donne déjà beaucoup d'outils bien utiles, mais dès qu'on sort des chemins battus on se fait suer pour calculer une différence entre deux dates ou plus bêtement le numéro du jour de l'année (32 pour le 1er février). Il suffit d'en avoir besoin une fois pour se dire que “pff… Il serait bon de stocker les quelques lignes quelque part…”
C'est le cadre idéal à la création d'une classe.

Comme d'habitude on commence par rêver, par imaginer comment on aimerait l'utiliser, cette classe.
On l'appèlerait GestionDates.
Comme on n'a pas besoin d'en manipuler des instances, l'idéal serait d'appeler ses méthodes directement. Imaginons une méthode numJour qui renverrait le numéro du jour de l'année :

// le .fla
 
import GestionDates
var laDate:Date=new Date("2010/2/1");
trace (GestionDates.numJour(laDate))

Normalement (du moins avec ce qu'on sait) invoquer une méthode c'est invoquer la méthode d'un objet de la classe (une instance de la classe). Si on écrit la classe GestionDates comme on sait le faire avec une méthode publique numJour

package {
 
	public class GestionDates {
 
		// numéro du jour depuis le premier janvier de la même année
		public function numJour(pD:Date):int {
			// retourne n'importe quoi le temps de tester
			return 88;
		}
	}
}

… et qu'on essaie de l'appeler comme dans nos rêves, on obtient une erreur à la compilation :

1061: Appel à la méthode numJour peut-être non définie, via la référence de type static Class.

Si je traduis ce que râle le compilateur ça donne : “Hey Machin ! Tu fais appel à une méthode statique numJour et je ne la trouve pas…”

Quoi statique ?! On n'a rien précisé…
Justement… Il se trouve qu'on peut invoquer une méthode de classe depuis la classe elle même, mais ça implique qu'elle soit statique. C'est ce qui a trompé le compilateur : il voit un appel direct, il se dit “tiens, une méthode statique”, il ne la trouve pas, il récrimine…

Ajoutez static devant le nom de fonction, ayé le tour est joué :)

                public static function numJour(pD:Date):int {
			// retourne n'importe quoi le temps de tester
			return 88;
		}
A noter :
Pas de this dans une fonction statique puisque il n'y a pas d'instance…

Constante statique

Travailler des dates implique de travailler avec des millisecondes, ce qui est loin d'être pratique… Le nombre de millisecondes contenues en un jour, autant se le calculer une bonne fois pour toutes et en faire une constante globale privée et statique elle aussi puisque concernant la classe et non ses instances. On la définit donc en haut du bloc classe comme suit :

		private static const msJour:Number=1000*60*60*24;

Il ne reste plus qu'à écrire les deux lignes qui vont bien dans la fonction :

		public static function numJour(pD:Date):int {
			var premierJour:Date=new Date(pD.fullYear,0,1);
			return (pD.getTime() - premierJour.getTime() ) /msJour+1;
		}

Et du coup à moindre frais on peut ajouter à cette classe une autre méthode dateDiff qui donne le nombre de jours entre deux dates :

		public static function dateDiff(pD1:Date,pD2:Date):int {
			return (pD1.getTime()-pD2.getTime())/msJour;
		}

C'était donc ça ! S'exclame Ronchon, en faisant référence à ce qu'on a mis en place quand on a vu comment diffuser un événement.
Hé oui, souvenez vous : avec nos boites modales on avait diffusé un événement BtClick, et pour respecter les conventions d'écriture, on avait sorti une constante statique BT_CLICK

public static const BT_CLICK:String="BtClick";

Ce qui nous permettait d'y accéder directement depuis la classe BoiteAlerte - et non depuis une de ses instances :

bteDemo.addEventListener(BoiteAlerte.BT_CLICK,compte);

Là aussi, force est de constater qu'on utilise des constantes statiques depuis tout le temps avec les classes natives… Je pense, par exemple, à la classe MouseEvent, une des premières qu'on utilise et qui expose MOUSE_DOWN, CLICK et autres ROLL_OVER.

Variable statique

On peut aussi déclarer une variable (ou une fonction) comme étant statique, au sein d'une classe qui instancie des objets.
Ne croyez pas que le mot clé static soit réservé aux classes qui n'instancient rien. Il signifie seulement que la variable en question qualifie la classe et non chacune de ses instances, ou que la méthode sera appelée depuis la classe et non depuis une de ses instances.

Une petite illustration plutôt qu'un long discours :

Soit une classe destinée à être associée à un symbole (donc instances) :

package {
	import flash.display.MovieClip;
 
	public class DemoStaticProp extends MovieClip {
                // une statique :
		public static var nbOccurences:int=0;
 
		public function DemoStaticProp() {
                        // statique incrémentée
			nbOccurences++;
			trace("constructeur "+ this+ " nb occurences "+ nbOccurences);
 
		}
	}
}

Du côté du .fla on associe un ou plusieurs symboles à cette classe (via le champ Classe de base) et on dispose des instances sur la scène :

Et on écrit une unique ligne en action d'image 1 :

trace("ds le fla je compte les instances : "+DemoStaticProp.nbOccurences);
constructeur [object Mv_Girafe] nb occurences 1
constructeur [object Mv_Elephant] nb occurences 2
constructeur [object Mv_Girafe] nb occurences 3
constructeur [object Mv_Elephant] nb occurences 4
constructeur [object Mv_Elephant] nb occurences 5
constructeur [object Mv_Girafe] nb occurences 6
ds le fla je compte les instances : 6

Pour finir la démonstration, occupons nous de faire en sorte que la variable de classe nbOccurences soit mise à jour quand on supprime une instance :

package {
	import flash.display.MovieClip;
	import flash.events.Event
 
	public class DemoStaticProp extends MovieClip {
		public static var nbOccurences:int=0;
 
		public function DemoStaticProp() {
			nbOccurences++;
			trace("constructeur "+ this+ " nb occurences "+ nbOccurences);
                        // Ecouter la suppression
			addEventListener(Event.REMOVED_FROM_STAGE, supprime);
		}
                // Quand supprimé nbOccurences décrémenté
		function supprime(e:Event) {
			nbOccurences--;
		}
	}
}

Dans le fla :

trace("ds le fla je compte les instances : "+DemoStaticProp.nbOccurences);
 
// j'écoute le clic sur enfants de la scène : argument true)
addEventListener(MouseEvent.CLICK, sup,true);
 
function sup(me:MouseEvent) {
	removeChild(MovieClip(me.target));
	trace("Il reste : "+DemoStaticProp.nbOccurences);
}

Conclusion

Voilà, non pas que tout soit dit…
Loin de là, mais j'espère que maintenant vous avez les idées claires et disposez du vocabulaire nécessaire à lire la doc ou des ouvrages traitant de POO AS3 sans butter sur tous les mots ;)

L'incontournable de Thibault Imbert

Un tuto classique sur les classes et la POO AS3 par Tannoy

Sans oublier la doc, bien sûr

Vous pourrez mettre en œuvre vos toutes fraiches connaissances via le tuto de Gnicos Déplacer un objet d'après les coordonnées de la souris.

Je vous remercie de m'avoir accompagnée jusque là, j'y ai gagné beaucoup à tout décortiquer de la sorte, je vous souhaite bonne route pour la suite et… à bientôt peut-être, quelque part dans les ressources, sait-on jamais… ;)