Documentation Flash CS3 |
|||
| Programmation avec ActionScript 3.0 > Programmation orientée objet en ActionScript > Rubriques avancées : | |||
Cette section débute par un bref historique d'ActionScript et de la programmation orientée objet, puis se poursuit par une présentation du modèle d'objet d'ActionScript 3.0 et de la façon dont il permet à la nouvelle machine virtuelle d'ActionScript (AVM2, ActionScript Virtual Machine 2) d'être nettement plus rapide que les versions antérieures de Flash Player, basées sur la première version de la machine virtuelle d'ActionScript, AVM1.
ActionScript 3.0 est une évolution des versions antérieures d'ActionScript, c'est pourquoi il peut être utile de comprendre l'évolution du modèle d'objet en ActionScript. ActionScript était à l'origine un simple mécanisme de script pour les premières versions de Flash. Les programmeurs Flash ont alors commencé à développer des applications de plus en plus complexes avec ActionScript. En réponse aux besoins de ces programmeurs, le langage de chaque nouvelle version a connu des ajouts destinés à faciliter la création d'applications complexes.
ActionScript 1.0 est le langage utilisé dans les versions 6 et antérieures de Flash Player. Même à ce stade précoce de développement, le modèle d'objet d'ActionScript était basé sur le concept de l'objet comme type fondamental de données. Un objet ActionScript est un type de données composite doté d'un groupe de propriétés. Dans le contexte d'un modèle d'objet, le terme propriétés désigne tout ce qui est affecté à un objet (variables, fonctions ou méthodes).
Bien que cette première génération d'ActionScript ne prenne pas en charge la définition de classes avec le mot-clé class, elle permet de définir une classe à l'aide d'un type spécial d'objet appelé objet prototype. Au lieu d'utiliser un mot-clé class pour créer une définition de classe abstraite qui sera ensuite instanciée en objets concrets (à l'instar des langages reposant sur des classes, comme Java ou C++), les langages basés sur le prototypage, tel qu'ActionScript 1.0, utilisent un objet existant comme modèle (ou prototype) d'autres objets. Alors que les objets des langages basés sur la notion de classes peuvent pointer sur une classe qui leur sert de modèle, les objets des langages basés sur la notion de prototypes pointent sur un autre objet, leur prototype, qui leur sert de modèle.
Pour créer une classe en ActionScript 1.0, il est nécessaire de définir une fonction constructeur pour cette classe. En ActionScript, les fonctions sont des objets réels et non pas de simples définitions abstraites. La fonction constructeur sert alors d'objet prototype pour les instances de cette classe. Le code suivant crée une classe nommée Shape et définit une propriété nommée visible, qui a la valeur true par défaut:
//classe de base
function Shape() {}
// création d'une propriété nommée 'visible'.
Shape.prototype.visible = true;
Cette fonction constructeur définit une classe Shape qui va être instanciée à l'aide de l'opérateur new, comme suit :
myShape = new Shape();
Just as the Shape() constructor function object serves as the prototype for instances of the Shape class, it can also serve as the prototype for subclasses of Shape--that is, other classes that extend the Shape class.
La création d'une classe qui est une sous-classe de la classe Shape est un processus en deux étapes. D'abord, créer la classe en définissant une fonction constructeur pour cette classe :
// classe enfant
function Circle(id, radius)
{
this.id = id;
this.radius = radius;
}
Ensuite, utiliser l'opérateur new pour déclarer que la classe Shape est le prototype de la classe Circle. Par défaut, toute nouvelle classe créée utilise la classe Object comme prototype, si bien que Circle.prototype contient alors un objet générique (une instance de la classe Object). Pour spécifier que le prototype de Circle est Shape et non pas Object, utilisez le code suivant pour changer la valeur de Circle.prototype afin qu'elle contienne un objet Shape et non plus un objet générique:
// faire de Circle une sous-classe de Shape. Circle.prototype = new Shape();
La classe Shape et la classe Circle sont maintenant liées par une relation d'héritage communément appelée chaînage du prototype. Le diagramme représente la relation au sein d'un chaînage de prototype :
La classe de base, à la fin de chaque chaînage de prototype, est la classe Object. La classe Object contient une propriété statique nommée Object.prototype qui pointe sur l'objet prototype de base pour tous les objets créés en ActionScript 1.0. Dans notre exemple de chaînage de prototype, l'objet suivant est l'objet Shape. En effet, la propriété Shape.prototype n'a jamais été explicitement définie, si bien qu'elle contient encore un objet générique (une instance de la classe Object). Le lien final de ce chaînage est la classe Circle, qui est liée à son prototype, la classe Shape (la propriété Circle.prototype contient un objet Shape).
Si nous créons une instance de la classe Circle, comme dans l'exemple ci-dessous, l'instance hérite du chaînage de prototype de la classe Circle :
//créer une instance de la classe Circle. myCircle = new Circle();
Vous vous souvenez sans doute que nous avons créé une propriété nommée visible comme membre de la classe Shape. Dans notre exemple, la propriété visible n'existe pas comme partie de l'objet myCircle, mais uniquement comme membre de l'objet Shape, et pourtant la ligne de code suivit produit true:
trace(myCircle.visible); // résultat : true
En remontant le chaînage du prototype, Flash Player est en mesure de vérifier que l'objet myCircle hérite de la propriété visible. Lorsque ce code est exécuté, Flash Player recherche d'abord dans les propriétés de l'objet myCircle une propriété nommée visible, mais ne la trouve pas. Flash Player recherche alors dans l'objet Circle.prototype, mais ne trouve toujours pas de propriété nommée visible. En continuant à remonter le chaînage du prototype, Flash Player trouve enfin la propriété visible, définie dans l'objet Shape.prototype, et affiche la valeur de cette propriété.
Pour des raisons de simplicité, cette section omet un grand nombre de détails et de complexités du chaînage de prototype, puisqu'il s'agit simplement de vous aider à comprendre le modèle d'objet en ActionScript 3.0.
Avec ActionScript 2.0 ont été introduits de nouveaux mots-clés tels que class, extends, public et private, qui permettaient de définir des classes selon une méthode familière à toute personne connaissant les langages basés sur des classes, comme Java et C++. Il est important de comprendre que le mécanisme sous-jacent d'héritage n'a pas changé entre ActionScript 1.0 et ActionScript 2.0. La nouveauté d'ActionScript 2.0 consistait simplement en une nouvelle syntaxe pour la définition des classes. Le chaînage du prototype fonctionne de la même façon dans ces deux versions du langage.
La nouvelle syntaxe introduite par ActionScript 2.0 est représentée dans l'exemple ci-dessous. Elle permet de définir des classes d'une façon que la plupart des programmeurs considèrent comme plus intuitive :
//classe de base
class Shape
{
var visible:Boolean = true;
}
Notez qu'ActionScript 2.0 a également introduit les annotations de type destinées à une vérification des types à la compilation. Elles permettent de déclarer que la propriété visible de l'exemple précédent ne doit contenir qu'une valeur booléenne. Le nouveau mot-clé extends simplifie lui aussi le processus de création d'une sous-classe. Dans l'exemple suivant, ce qui nécessitait deux étapes en ActionScript 1.0 est accompli en une seule étape, à l'aide du mot-clé extends :
// classe enfant
class Circle extends Shape
{
var id:Number;
var radius:Number;
function Circle(id, radius)
{
this.id = id;
this.radius = radius;
}
}
Le constructeur est maintenant déclaré dans le cadre de la définition de classe, et les propriétés id et radius de la classe doivent elles aussi être déclarées explicitement.
ActionScript 2.0 a également ajouté la prise en charge de la définition des interfaces, qui permet de rendre plus sophistiqués des programmes orientés objet à l'aide de protocoles formellement définis pour la communication entre les objets.
Un paradigme courant en programmation orientée objet, en particulier avec Java et C++, fait appel à des classes pour définir des types d'objets. Les langages de programmation qui adoptent ce paradigme ont aussi tendance à utiliser des classes pour construire des instances du type de données défini par la classe. ActionScript utilise des classes pour ces deux buts, mais ses origines de langage basé sur des prototypes lui confèrent une caractéristique intéressante. Pour chaque définition de classe, ActionScript crée un objet de classe spécial qui autorise le partage du comportement et de l'état. Pour de nombreux programmeurs en ActionScript, toutefois, cette distinction n'aura aucune implication pratique sur le codage. En effet, ActionScript 3.0 est conçu de telle sorte qu'il est possible de créer des applications sophistiquées orientées objet sans utiliser, et sans même comprendre, ces objets de classe spéciaux. Cette section étudie en détail les problèmes que rencontreront les programmeurs avancés qui souhaitent tirer parti des objets de classe.
Le diagramme suivant montre la structure d'un objet de classe représentant une classe simple nommée A, définie par l'instruction class A {}:
Chaque rectangle du diagramme représente un objet. Chaque objet du diagramme est marqué d'un caractère en indice A pour signaler qu'il appartient à la classe A. L'objet de classe (CA) contient des références à un certain nombre d'autres objets importants. L'objet traits des instances (TA) enregistre les propriétés des instances qui sont définies dans une définition de classe. Un objet traits de la classe (TCA) représente le type interne de la classe et enregistre les propriétés statiques définies par la classe (le caractère C en indice signifie « classe »). L'objet prototype (PA) fait toujours référence à l'objet de classe auquel il était attaché à l'origine via la propriété constructeur.
L'objet traits est une nouveauté d'ActionScript 3.0 qui a été implémentées pour des raisons de performances. Dans les versions précédentes d'ActionScript, la recherche d'un nom pouvait nécessiter beaucoup de temps pendant que Flash Player remontait le chaînage du prototype. En ActionScript 3.0, la recherche d'un nom est beaucoup plus rapide et efficace, car les propriétés héritées sont copiées des super-classes dans l'objet traits des sous-classes.
L'objet traits n'est pas directement accessible par code, mais sa présence se manifeste par l'amélioration des performances et de l'utilisation mémoire. L'objet traits fournit à la machine virtuelle AVM2 des informations détaillées sur la disposition et le contenu d'une classe. Ces informations permettent à AVM2 de réduire nettement le temps d'exécution, car elle peut fréquemment générer des instructions machine directes pour accéder à des propriétés ou appeler des méthodes directement, sans effectuer au préalable une longue recherche de nom.
Grâce à l'objet traits, l'espace occupé en mémoire par un objet peut être nettement moins importante qu'avec les versions antérieures d'ActionScript. Par exemple, si une classe est scellée (c'est-à-dire si cette classe n'est pas déclarée comme dynamique), une instance de la classe ne nécessite pas de recherche par calcul d'adresse pour les propriétés ajoutées dynamiquement, et il lui suffit d'un pointeur sur l'objet traits et de quelques emplacements pour les propriétés fixes définies dans la classe. En conséquence, pour un objet qui nécessitait 100 octets en mémoire avec ActionScript 2.0, 20 octets suffiront avec ActionScript 3.0.
|
REMARQUE |
|
L'objet traits est un élément d'implémentation interne et il n'est pas garanti qu'il ne changera pas, ou même qu'il ne disparaîtra pas, dans les versions futures d'ActionScript. |
En ActionScript , chaque objet de classe possède une propriété nommée prototype, qui est une référence à l'objet prototype de cette classe. L'objet prototype est un héritage des premières versions d'ActionScript, basées sur des prototypes. Pour plus d'informations, consultez la section ActionScript 1.0.
La propriété prototype est en lecture seule et ne peut donc pas être modifiée pour pointer sur d'autres objets. À l'inverse, dans les anciennes versions d'ActionScript, la propriété prototype pouvait être réaffectée pour pointer sur une autre classe. Bien que la propriété prototype soit en lecture seule, ce n'est pas le cas de l'objet prototype qu'elle référence. De nouvelles propriétés peuvent donc être ajoutées à l'objet prototype. Les propriétés ajoutées à l'objet prototype sont partagées avec toutes les autres instances de la classe.
Le chaînage de prototype, qui était le seul mécanisme d'héritage des versions antérieures d'ActionScript, n'a plus qu'un rôle secondaire en ActionScript 3.0. Le principal mécanisme d'héritage, l'héritage des propriétés fixes, est géré de façon interne par l'objet traits. Une propriété fixe est une variable ou une méthode définie dans le cadre d'une définition de classe. L'héritage des propriétés fixes est également appelé héritage des classes, car c'est le mécanisme d'héritage qui est associé aux mots-clés class, extends et override.
Le chaînage de prototype représente un autre mécanisme d'héritage qui est plus dynamique que l'héritage des propriétés fixes. Il est possible d'ajouter des propriétés à l'objet prototype d'une classe non seulement dans le cadre de la définition de classe, mais aussi lors de l'exécution, via la propriété prototype de l'objet de classe. Notez toutefois que si le compilateur est en mode strict, il peut être impossible d'accéder aux propriétés ajoutées à un objet prototype, sauf si vous déclarez une classe avec le mot-clé dynamic.
La classe Object est un bon exemple d'une classe dont plusieurs propriétés sont attachées à l'objet prototype. Les méthodes toString() et valueOf() de la classe Object sont en fait des fonctions affectées à des propriétés de l'objet prototype de la classe Object. Voici un exemple de l'aspect théorique de la déclaration de ces méthodes (l'implémentation réelle est légèrement différente en raison des détails pratiques d'implémentation) :
public dynamic class Object
{
prototype.toString = function()
{
//instructions
};
prototype.valueOf = function()
{
//instructions
};
}
Comme nous l'avons déjà mentionné, il est possible d'attacher une propriété à l'objet prototype d'une classe en-dehors de la définition de cette classe. Par exemple, la méthode toString() peut également être définie hors de la définition de la classe Object, comme suit :
Object.prototype.toString = function()
{
//instructions
};
Toutefois, contrairement à l'héritage des propriétés fixes, l'héritage du prototype ne nécessite pas le mot-clé override pour redéfinir une méthode d'une sous-classe. Par exemple, pour redéfinir la méthode valueOf() dans une sous-classe de la classe Object, trois options sont possibles. Premièrement, vous pouvez définir une méthode valueOf() dans l'objet prototype de la sous-classe, à l'intérieur de la définition de classe. Le code suivant crée une sous-classe d'Object nommée Foo, et redéfinit la méthode valueOf() dans la définition de classe de l'objet prototype de Foo. Chaque classe héritant de la classe Object, il n'est pas nécessaire d'utiliser le mot-clé extends.
dynamic class Foo
{
prototype.valueOf = function()
{
return "Instance of Foo";
};
}
Deuxièmement, vous pouvez définir une méthode valueOf() dans l'objet prototype de Foo en-dehors de la définition de classe, comme le montre le code ci-dessous :
Foo.prototype.valueOf = function()
{
return "Instance of Foo";
};
Troisièmement, vous pouvez définir une propriété fixe nommée valueOf() dans la classe Foo. Cette technique diffère des précédentes dans la mesure où elle mêle l'héritage des propriétés fixes et l'héritage du prototype. Pour redéfinir valueOf() à partir d'une sous-classe de Foo, il est nécessaire d'utiliser le mot-clé override. Le code ci-dessous montre valueOf() définie comme propriété fixe dans Foo :
class Foo
{
function valueOf():String
{
return "Instance of Foo";
}
}
L'existence de deux mécanismes d'héritage séparés, l'héritage des propriétés fixes et l'héritage du prototype, provoque un intéressant problème de compatibilité par rapport aux propriétés et méthodes des classe de base. La compatibilité avec les spécifications préliminaires du langage ECMAScript, édition 4, nécessite d'utiliser l'héritage de prototype, si bien que les propriétés et méthodes d'une classe de base sont définies dans l'objet prototype de cette classe. Mais par ailleurs, la compatibilité avec l'API de Flash Player nécessite d'utiliser l'héritage des propriétés fixes, si bien que les propriétés et méthodes d'une classe de base sont définies dans la définition de classe, à l'aide des mots-clés const, var et function. De plus, l'utilisation des propriétés fixes au lieu des versions du prototype est susceptible de permettre une nette amélioration des performances à l'exécution.
Pour résoudre ce problème, ActionScript 3.0 utilise les deux mécanismes d'héritage (propriétés fixes et prototype) pour les classes de base. Chaque classe de base contient deux jeux de propriétés et de méthodes. Un jeu est défini dans l'objet prototype pour assurer la compatibilité avec les spécifications d'ECMAScript, et l'autre jeu est défini avec les propriétés fixes et l'espace de nom d'AS3, pour assurer la compatibilité avec l'API de Flash Player.
L'espace de nom d'AS3 représente un mécanisme fort pratique pour choisir entre les deux jeux de propriétés et de méthodes. Si vous n'utilisez pas l'espace de nom d'AS3, une instance d'une classe de base hérite des propriétés et des méthodes définies dans l'objet prototype de cette classe de base. Si par contre vous utilisez l'espace de nom d'AS3, une instance d'une classe de base hérite des versions d'AS3, car les propriétés fixes sont toujours préférées aux propriétés du prototype. En d'autres termes, lorsqu'une propriété fixe est disponible, elle est toujours utilisée à la place d'une propriété du prototype ayant le même nom.
Il est possible d'utiliser sélectivement la version de l'espace de nom d'AS3 d'une propriété ou d'une méthode, en la qualifiant à l'aide de l'espace de nom d'AS3. Par exemple, le code ci-dessous utilise la version AS3 de la méthode Array.pop() :
var nums:Array = new Array(1, 2, 3); nums.AS3::pop(); trace(nums); // résultat : 1,2
Vous pouvez aussi faire appel à la directive use namespace pour ouvrir l'espace de nom d'AS3 pour toutes les définitions figurant dans un bloc de code. Par exemple, le code ci-dessous utilise la directive use namespace pour ouvrir l'espace de nom d'AS3 pour les méthodes pop() et push():
use namespace AS3; var nums:Array = new Array(1, 2, 3); nums.pop(); nums.push(5); trace(nums) // résultat : 1,2,5
ActionScript 3.0 comporte aussi des options de compilation pour chaque jeu de propriétés, ce qui permet d'appliquer l'espace de nom d'AS3 au programme entier. L'option de compilation -as3 représente l'espace de nom d'AS3, et l'option de compilation -es représente l'option d'héritage du prototype (es signifie ECMAScript). Pour ouvrir l'espace de nom d'AS3 pour tout le programme, mettez l'option de compilation -as3 sur true et l'option de compilation -es sur false. Pour utiliser les versions du prototype, mettez les options de compilation sur les valeurs opposées. Les options de compilation par défaut pour Adobe Flex Builder 2 et Adobe Flash CS3 Professional sont -as3 = true et -es = false.
Si vous prévoyez d'étendre l'une des classes de base et de redéfinir des méthodes, vous devez comprendre comment l'espace de nom d'AS3 affecte la façon de déclarer une méthode redéfinie. Si vous utilisez l'espace de nom d'AS3, toute redéfinition d'une méthode d'une classe de base doit également utiliser l'espace de nom d'AS3, ainsi que l'attribut override. Si vous n'utilisez pas l'espace de nom d'AS3 et voulez redéfinir une méthode d'une classe de base dans une sous-classe, vous ne devez utiliser ni l'espace de nom d'AS3 dans cette redéfinition, ni l'attribut override.
Flash CS3
M'envoyer un message électronique lorsque des commentaires sont ajoutés à cette page | Rapport de commentaire
Page en cours: http://livedocs.adobe.com/flash/9.0_fr/main/00000069.html