Les espaces de noms vous permettent de contrôler la visibilité des propriétés et des méthodes que vous créez. Considérez les spécificateurs de contrôle d’accès public, private, protected et internal comme des espaces de noms intégrés. Si ces spécificateurs de contrôle d’accès prédéfinis ne répondent pas à vos besoins, vous pouvez créer vos propres espaces de noms.
Si vous avez l’habitude d’utiliser des espaces de noms XML, cette section ne vous fournira pas de nouvelles informations, bien que la syntaxe et les détails de l’implémentation d’ActionScript soient légèrement différents de ceux d’XML. Si vous n’avez jamais travaillé avec des espaces de noms, le concept est simple, mais l’implémentation possède une terminologie particulière que vous devrez apprendre.
Pour comprendre comment fonctionnent les espaces de noms, il convient de savoir que le nom d’une propriété ou d’une méthode contient deux parties : un identifiant et un espace de noms. L’identifiant est ce que vous considérez généralement comme un nom. Par exemple, les identifiants dans la définition de classe suivante sont sampleGreeting et sampleFunction() :
class SampleCode
{
var sampleGreeting:String;
function sampleFunction () {
trace(sampleGreeting + " from sampleFunction()");
}
}
Lorsque les définitions ne sont pas précédées d’un attribut d’espace de noms, leurs noms sont qualifiés par l’espace de noms internal par défaut, ce qui signifie qu’ils sont visibles uniquement aux appelants du même package. Si le compilateur est défini sur le mode strict, il génère un avertissement indiquant que l’espace de noms internal s’applique à tout identifiant sans attribut d’espace de noms. Pour vérifier qu’un identifiant est disponible partout, vous devez spécifiquement faire précéder le nom de l’identifiant de l’attribut public. Dans l’exemple de code précédent, sampleGreeting et sampleFunction() ont une valeur d’espace de noms d’internal.
Vous devez suivre trois étapes de base lorsque vous utilisez des espaces de noms. Premièrement, vous devez définir l’espace de noms à l’aide du mot-clé namespace. Par exemple, le code suivant définit l’espace de noms version1 :
namespace version1;
Deuxièmement, vous appliquez votre espace de noms en l’utilisant à la place d’un spécificateur de contrôle d’accès dans une déclaration de méthode ou de propriété. L’exemple suivant place une fonction appelée myFunction() dans l’espace de noms version1 :
version1 function myFunction() {}
Troisièmement, une fois que vous avez appliqué l’espace de noms, vous pouvez le référencer à l’aide de la directive use ou en qualifiant le nom d’un identifiant avec un espace de nom. L’exemple suivant fait référence à la fonction myFunction() à l’aide de la directive use :
use namespace version1;
myFunction();
Vous pouvez également utiliser un nom qualifié pour référencer la fonction myFunction(), comme l’indique l’exemple suivant :
version1::myFunction();
Définition des espaces de noms
Les espaces de noms contiennent une valeur, l’URI (Uniform Resource Identifier), parfois appelée nom d’espace de noms. Un URI vous permet de vérifier que votre définition d’espace de noms est unique.
Vous créez un espace de noms en déclarant sa définition de deux façons différentes. Vous pouvez soit définir un espace de noms avec un URI explicite, comme vous définiriez un espace de noms XML, soit omettre l’URI. L’exemple suivant indique comment un espace de noms peut être défini à l’aide d’un URI :
namespace flash_proxy = "http://www.adobe.com/flash/proxy";
L’URI sert de chaîne d’identification unique pour cet espace de noms. Si vous omettez l’URI, comme dans l’exemple suivant, le compilateur crée une chaîne d’identification interne unique à la place. Vous n’avez pas accès à cette chaîne d’identification interne.
namespace flash_proxy;
Une fois que vous avez défini un espace de noms (avec ou sans URI), vous ne pouvez pas le redéfinir dans le même domaine. Une tentative de définition d’un espace de noms ayant été défini dans le même domaine génère une erreur du compilateur.
Si un espace de noms est défini dans un package ou une classe, il risque de ne pas être visible au code externe à ce package ou à cette classe, à moins que vous n’utilisiez le spécificateur de contrôle d’accès approprié. Par exemple, le code suivant indique l’espace de noms flash_proxy défini dans le package flash.utils. Dans l’exemple suivant, l’absence de spécificateur de contrôle d’accès signifie que l’espace de noms flash_proxy est visible uniquement au code dans le package flash.utils et non au code externe au package :
package flash.utils
{
namespace flash_proxy;
}
Le code suivant utilise l’attribut public pour rendre l’espace de noms flash_proxy visible au code externe au package :
package flash.utils
{
public namespace flash_proxy;
}
Application d’espaces de noms
Appliquer un espace de noms signifie placer une définition dans un espace de noms. Les définitions que vous pouvez placer dans des espaces de noms peuvent être des fonctions, des variables et des constantes (vous ne pouvez pas placer une classe dans un espace de noms personnalisé).
Supposez, par exemple, qu’une fonction soit déclarée à l’aide de l’espace de noms de contrôle d’accès public. L’utilisation de l’attribut public dans une définition de fonction place la fonction dans l’espace de noms public et la rend visible à tout le code. Une fois que vous avez défini un espace de noms, vous pouvez l’utiliser de la même façon que l’attribut public, et la définition est disponible pour le code pouvant référencer votre espace de noms personnalisé. Par exemple, si vous définissez un espace de noms example1, vous pouvez ajouter une méthode appelée myFunction() à l’aide de example1 comme attribut, tel que l’indique l’exemple suivant :
namespace example1;
class someClass
{
example1 myFunction() {}
}
Déclarer la méthode myFunction() à l’aide de l’espace de noms example1 comme attribut signifie que la méthode appartient à l’espace de noms example1.
Tenez compte des points suivants lorsque vous appliquez des espaces de noms :
Vous pouvez appliquer un seul espace de noms à chaque déclaration.
Il n’existe aucun moyen d’appliquer un attribut d’espace de noms à plusieurs définitions simultanément. En d’autres termes, si vous souhaitez appliquer votre espace de noms à dix fonctions différentes, vous devez ajouter votre espace de noms comme attribut à chacune des dix définitions de fonction.
Si vous appliquez un espace de noms, vous ne pouvez pas spécifier un spécificateur de contrôle d’accès car les espaces de noms et les spécificateurs de contrôle d’accès s’excluent mutuellement. En d’autres termes, vous ne pouvez pas déclarer une fonction ou une propriété comme public, private, protected ou internal si vous appliquez votre espace de noms.
Référence d’espaces de noms
Il est inutile de référencer explicitement un espace de noms lorsque vous utilisez une méthode ou une propriété déclarée avec l’un des espaces de noms de contrôle d’accès (public, private, protected et internal, par exemple). En effet, l’accès à ces espaces de noms spéciaux dépend du contexte. Par exemple, les définitions placées dans l’espace de noms private sont automatiquement disponibles pour le code dans la même classe. Pour les espaces de noms que vous définissez, cependant, le contexte ne compte pas. Pour utiliser une méthode ou une propriété que vous avez placée dans un espace de noms personnalisé, vous devez référencer celui-ci.
Vous pouvez référencer des espaces de noms avec la directive use namespace ou qualifier le nom avec l’espace de noms à l’aide du ponctuateur de qualificatif de nom (::). Le fait de référencer un espace de noms avec la directive use namespace ouvre l’espace de noms, ce qui permet de l’appliquer à n’importe quel identifiant non qualifié. Par exemple, si vous avez défini l’espace de noms example1, vous pouvez accéder aux noms dans cet espace de noms en utilisant use namespace example1 :
use namespace example1;
myFunction();
Vous pouvez ouvrir plusieurs espaces de noms simultanément. Une fois que vous avez ouvert un espace de noms avec use namespace, il reste ouvert dans le bloc de code dans lequel il a été ouvert. Il n’existe aucun moyen pour fermer explicitement un espace de noms.
Néanmoins, le fait d’avoir plusieurs espaces de noms ouverts augmente la probabilité que des conflits de noms se produisent. Si vous préférez ne pas ouvrir d’espace de noms, vous pouvez éviter la directive use namespace en qualifiant le nom de la propriété ou de la méthode avec l’espace de noms et le ponctuateur de qualificatif de nom. Par exemple, le code suivant indique comment vous pouvez qualifier le nom myFunction() avec l’espace de noms example1 :
example1::myFunction();
Utilisation d’espaces de noms
Vous pouvez trouver un exemple d’espace de noms, tiré du monde réel, utilisé pour éviter des conflits sur les noms dans la classe flash.utils.Proxy qui fait partie d’ActionScript 3.0. La classe Proxy, qui remplace la propriété Object.__resolve d’ActionScript 2.0, vous permet d’intercepter les références aux propriétés ou aux méthodes non définies avant qu’une erreur ne se produise. Toutes les méthodes de la classe Proxy se trouvent dans l’espace de noms flash_proxy afin d’empêcher les conflits de noms.
Pour mieux comprendre comment l’espace de noms flash_proxy est utilisé, vous devez savoir comment utiliser la classe Proxy. La fonctionnalité de la classe Proxy est disponible uniquement aux classes qui héritent d’elle. En d’autres termes, si vous souhaitez utiliser les méthodes de la classe Proxy d’un objet, la définition de classe de l’objet doit étendre la classe Proxy. Par exemple, si vous souhaitez intercepter des tentatives d’appel d’une méthode non définie, vous devez étendre la classe Proxy puis remplacer la méthode callProperty() de la classe Proxy.
L’implémentation des espaces de noms est généralement un processus en trois étapes (définition, application et référence d’un espace de noms). Etant donné que vous n’appelez jamais explicitement une méthode de la classe Proxy, cependant, l’espace de noms flash_proxy est défini et appliqué uniquement, jamais référencé. ActionScript 3.0 définit l’espace de noms flash_proxy et l’applique dans la classe Proxy. Votre code doit uniquement appliquer l’espace de noms flash_proxy à des classes qui étendent la classe Proxy.
L’espace de noms flash_proxy est défini dans le package flash.utils comme illustré ci-dessous :
package flash.utils
{
public namespace flash_proxy;
}
L’espace de noms est appliqué aux méthodes de la classe Proxy comme indiqué dans l’extrait suivant issu de la classe Proxy :
public class Proxy
{
flash_proxy function callProperty(name:*, ... rest):*
flash_proxy function deleteProperty(name:*):Boolean
...
}
Comme l’indique le code suivant, vous devez d’abord importer la classe Proxy et l’espace de noms flash_proxy. Vous devez ensuite déclarer votre classe de façon à ce qu’elle étende la classe Proxy (vous devez également ajouter l’attribut dynamic si vous compilez en mode strict). Lorsque vous remplacez la méthode callProperty(), vous devez utiliser l’espace de noms flash_proxy.
package
{
import flash.utils.Proxy;
import flash.utils.flash_proxy;
dynamic class MyProxy extends Proxy
{
flash_proxy override function callProperty(name:*, ...rest):*
{
trace("method call intercepted: " + name);
}
}
}
Si vous créez une occurrence de la classe MyProxy et appelez une méthode non définie (la méthode testing() appelée dans l’exemple suivant, par exemple), votre objet Proxy intercepte l’appel de méthode et exécute les instructions se trouvant dans la méthode callProperty() remplacée (dans ce cas, une instruction trace() simple).
var mySample:MyProxy = new MyProxy();
mySample.testing(); // method call intercepted: testing
Le fait que les méthodes de la classe Proxy se trouvent dans l’espace de noms flash_proxy présente deux avantages. Premièrement, le fait d’avoir un espace de noms séparé réduit l’encombrement dans l’interface publique des classes qui étendent la classe Proxy (iI existe environ douze méthodes dans la classe Proxy que vous pouvez remplacer. Elles ne sont pas conçues pour être appelées directement. Le fait de toutes les placer dans l’espace de noms public peut prêter à confusion). Deuxièmement, le fait d’utiliser l’espace de noms flash_proxy évite les conflits de nom si votre sous-classe Proxy contient des méthodes d’occurrence avec des noms correspondant à l’une des méthodes de la classe Proxy. Par exemple, vous pouvez nommer l’une de vos méthodes callProperty(). Le code suivant est acceptable car votre version de la méthode callProperty() se trouve dans un espace de noms différent :
dynamic class MyProxy extends Proxy
{
public function callProperty() {}
flash_proxy override function callProperty(name:*, ...rest):*
{
trace("method call intercepted: " + name);
}
}
Vous pouvez également utiliser des espaces de noms pour accéder à des méthodes ou à des propriétés autrement qu’avec les quatre spécificateurs de contrôle d’accès (public, private, internal et protected). Par exemple, vous pouvez avoir des méthodes d’utilitaire éparpillées sur plusieurs packages. Vous souhaitez que ces méthodes soient disponibles pour tous vos packages, mais vous ne souhaitez pas qu’elles soient publiques. Pour cela, vous pouvez créer un espace de noms et l’utiliser comme spécificateur de contrôle d’accès spécial.
L’exemple suivant utilise un espace de noms défini par l’utilisateur pour regrouper deux fonctions se trouvant dans différents packages. En les regroupant dans le même espace de noms, vous pouvez rendre les deux fonctions visibles à une classe ou à un package au moyen d’une seule instruction use namespace.
Cet exemple utilise quatre fichiers pour démontrer la technique. Tous les fichiers doivent se trouver dans votre chemin de classe. Le premier fichier, myInternal.as, sert à définir l’espace de noms myInternal. Etant donné que le fichier se trouve dans un package appelé example, vous devez placer le fichier dans un dossier appelé example. L’espace de noms est marqué comme public pour pouvoir être importé dans d’autres packages.
// myInternal.as in folder example
package example
{
public namespace myInternal = "http://www.adobe.com/2006/actionscript/examples";
}
Le deuxième et le troisième fichiers, Utility.as et Helper.as, définissent les classes qui contiennent des méthodes devant être disponibles pour d’autres packages. La classe Utility se trouve dans le package example.alpha, ce qui signifie que le fichier doit être placé dans un dossier appelé alpha qui est un sous-dossier du dossier example. La classe Helper se trouve dans le package example.beta, ce qui signifie que le fichier doit être placé dans un dossier appelé beta qui est également un sous-dossier du dossier example. Ces deux packages, example.alpha et example.beta, doivent importer l’espace de noms avant de l’utiliser.
// Utility.as in the example/alpha folder
package example.alpha
{
import example.myInternal;
public class Utility
{
private static var _taskCounter:int = 0;
public static function someTask()
{
_taskCounter++;
}
myInternal static function get taskCounter():int
{
return _taskCounter;
}
}
}
// Helper.as in the example/beta folder
package example.beta
{
import example.myInternal;
public class Helper
{
private static var _timeStamp:Date;
public static function someTask()
{
_timeStamp = new Date();
}
myInternal static function get lastCalled():Date
{
return _timeStamp;
}
}
}
Le quatrième fichier, NamespaceUseCase.as, est la classe de l’application principale et doit être un frère pour le dossier example. Dans Flash Professional, cette classe ferait office de classe de document du fichier FLA. La classe NamespaceUseCase importe également l’espace de noms myInternal et l’utilise pour appeler les deux méthodes statiques qui résident dans les autres packages. L’exemple utilise des méthodes statiques pour simplifier le code uniquement. Les méthodes statiques et d’occurrence peuvent être placées dans l’espace de noms myInternal.
// NamespaceUseCase.as
package
{
import flash.display.MovieClip;
import example.myInternal; // import namespace
import example.alpha.Utility;// import Utility class
import example.beta.Helper;// import Helper class
public class NamespaceUseCase extends MovieClip
{
public function NamespaceUseCase()
{
use namespace myInternal;
Utility.someTask();
Utility.someTask();
trace(Utility.taskCounter); // 2
Helper.someTask();
trace(Helper.lastCalled); // [time someTask() was last called]
}
}
}