Met naamruimten kunt u de zichtbaarheid beheren van de eigenschappen en methoden die u maakt. U kunt de toegangsbeheerspecificaties public, private, protected en internal zien als ingebouwde naamruimten. Als deze vooraf gedefinieerde toegangsbeheerspecificaties niet voldoen aan uw behoeften, kunt u zelf naamruimten maken.
Als u ervaring hebt met XML-naamruimten, zal het meeste u bekend voorkomen. De syntaxis en details voor de implementatie van ActionScript verschillen echter iets van die van XML. Als u nog nooit met naamruimten hebt gewerkt, zult u merken dat het concept zelf eenvoudig is, maar dat bij de implementatie specifieke terminologie wordt gebruikt die u moet leren kennen.
Als u wilt begrijpen hoe naamruimten werken, is het nuttig om te weten dat de naam van een eigenschap of methode altijd twee gedeelten bevat: een id en een naamruimte. De id is wat gewoonlijk als naam wordt beschouwd. De id's in de volgende klassendefinitie zijn bijvoorbeeld sampleGreeting en sampleFunction():
class SampleCode
{
var sampleGreeting:String;
function sampleFunction () {
trace(sampleGreeting + " from sampleFunction()");
}
}
Wanneer definities niet door een naamruimte-attribuut worden voorafgegaan, worden de namen ervan gekwalificeerd door de standaardnaamruimte internal. Dit betekent dat ze alleen zichtbaar zijn voor aanroepende elementen in hetzelfde pakket. Als de compiler is ingesteld op de strikte modus, wordt een waarschuwing weergegeven dat de naamruimte internal van toepassing is op alle id's zonder naamruimte-attribuut. Als u een id overal beschikbaar wilt maken, moet u de id-naam specifiek vooraf laten gaan door het attribuut public. In de voorgaande voorbeeldcode hebben zowel sampleGreeting als sampleFunction() de naamruimtewaarde internal.
Er zijn drie basisstappen voor het gebruiken van naamruimten. Als eerste stap definieert u de naamruimte met behulp van het trefwoord namespace. Met de volgende code wordt bijvoorbeeld de naamruimte version1 gedefinieerd:
namespace version1;
Als tweede stap past u de naamruimte toe door deze te gebruiken in plaats van een toegangsbeheerspecificatie in een eigenschap- of methodedeclaratie. In het volgende voorbeeld wordt een functie met de naam myFunction() in de naamruimte version1 geplaatst:
version1 function myFunction() {}
Als derde stap, nadat u de naamruimte hebt toegepast, kunt u ernaar verwijzen met de aanwijzing use of door de naam van een id met een naamruimte te kwalificeren. In het volgende voorbeeld wordt naar een functie met de naam myFunction() verwezen met behulp van de aanwijzing use:
use namespace version1;
myFunction();
U kunt ook een gekwalificeerde naam gebruiken om te verwijzen naar de functie myFunction(), zoals in het volgende voorbeeld wordt getoond:
version1::myFunction();
Naamruimten definiëren
Naamruimten bevatten één waarde, de URI (Uniform Resource Identifier), ook wel de naamruimtenaam genoemd. Met een URI weet u zeker dat de naamruimtedefinitie uniek is.
U maakt een naamruimte door op een van de twee mogelijke manieren een naamruimtedefinitie te declareren. U kunt een naamruimte definiëren met een expliciete URI, zoals bij een XML-naamruimte, of u kunt de URI weglaten. Het volgende voorbeeld laat zien hoe u een naamruimte kunt definiëren met een URI:
namespace flash_proxy = "http://www.adobe.com/flash/proxy";
De URI dient als unieke id-tekenreeks voor de naamruimte. Als u de URI weglaat, zoals in het volgende voorbeeld, wordt door de compiler een unieke interne id-tekenreeks gemaakt in plaats van de URI. U hebt geen toegang tot deze interne id-tekenreeks.
namespace flash_proxy;
Nadat u een naamruimte hebt gedefinieerd, met of zonder URI, kunt u die naamruimte niet opnieuw definiëren in hetzelfde bereik. Een poging om een naamruimte te definiëren die al in hetzelfde bereik is gedefinieerd, resulteert in een compilatiefout.
Als een naamruimte is gedefinieerd binnen een pakket of een klasse, is de naamruimte mogelijk niet zichtbaar voor code buiten dat pakket of de klasse, tenzij de juiste toegangsbeheerspecificatie wordt gebruikt. Met de volgende code wordt bijvoorbeeld de naamruimte flash_proxy getoond, gedefinieerd binnen het pakket flash.utils. In het voorbeeld betekent het ontbreken van een toegangsbeheerspecificatie dat de naamruimte flash_proxy alleen zichtbaar is voor code binnen het pakket flash.utils en niet voor andere code buiten het pakket:
package flash.utils
{
namespace flash_proxy;
}
Met de volgende code wordt het attribuut public gebruikt om de naamruimte flash_proxy zichtbaar te maken voor code buiten het pakket:
package flash.utils
{
public namespace flash_proxy;
}
Naamruimten toepassen
Een naamruimte toepassen betekent een definitie plaatsen in een naamruimte. Definities die u in naamruimten kunt plaatsen zijn functies, variabelen en constanten (u kunt geen klasse in een aangepaste naamruimte plaatsen).
Neem bijvoorbeeld een functie die is gedeclareerd met de toegangsbeheernaamruimte public. Door het gebruik van het attribuut public in een functiedefinitie wordt de functie in de naamruimte public geplaatst en is zo beschikbaar voor alle code. Nadat u een naamruimte hebt gedefinieerd, kunt u de gedefinieerde naamruimte net zo gebruiken als het attribuut public. De definitie is dan beschikbaar voor code die naar de aangepaste naamruimte kan verwijzen. Als u bijvoorbeeld een naamruimte example1 definieert, kunt u een methode met de naam myFunction() toevoegen door example1 als attribuut te gebruiken, zoals in het volgende voorbeeld wordt getoond:
namespace example1;
class someClass
{
example1 myFunction() {}
}
Door de methode myFunction() te declareren met de naamruimte example1 als attribuut, behoort de methode tot de naamruimte example1.
Let op het volgende wanneer u naamruimten toepast:
U kunt slechts één naamruimte toepassen op elke declaratie.
U kunt een naamruimte-attribuut nooit op meer dan één definitie tegelijk toepassen. Met andere woorden, als u een naamruimte wilt toepassen op tien verschillende functies, moet u de naamruimte als attribuut toevoegen aan elk van de tien functiedefinities.
Als u een naamruimte toepast, kunt u geen toegangsbeheerspecificatie opgeven, omdat naamruimten en toegangsbeheerspecificaties elkaar uitsluiten. Met andere woorden, u kunt een functie of eigenschap niet declareren als public, private, protected of internal nadat u de naamruimte hebt toegepast.
Verwijzen naar naamruimten
U hoeft niet expliciet naar een naamruimte te verwijzen wanneer u een methode of eigenschap gebruikt die wordt gedeclareerd met een van de toegangsbeheernaamruimten, zoals public, private, protected en internal. Dat komt doordat de toegang tot deze speciale naamruimten wordt bepaald door de context. Definities die bijvoorbeeld in de naamruimte private worden geplaatst, zijn automatisch beschikbaar voor code binnen dezelfde klasse. Voor naamruimten die u zelf definieert, bestaat een dergelijke contextgevoeligheid echter niet. Als u een methode of eigenschap wilt gebruiken die u in een aangepaste naamruimte hebt geplaatst, moet u naar de naamruimte verwijzen.
U kunt naar naamruimten verwijzen met de aanwijzing use namespace of u kunt de naam met de naamruimte kwalificeren met behulp van het naamkwalificatieteken (::). Door naar een naamruimte te verwijzen met de aanwijzing use namespace wordt de naamruimte 'geopend'. Zo kan de naamruimte worden toegepast op alle id's die niet zijn gekwalificeerd. Als u bijvoorbeeld de naamruimte example1 hebt gedefinieerd, hebt u toegang tot namen in die naamruimte door use namespace example1 te gebruiken:
use namespace example1;
myFunction();
U kunt meerdere naamruimten tegelijk openen. Nadat u een naamruimte hebt geopend met use namespace, blijft deze open voor het blok met code waarin de naamruimte is geopend. U kunt een naamruimte niet expliciet sluiten.
Als u meer dan één naamruimte open hebt, neemt de kans op naamconflicten echter toe. Als u een naamruimte liever niet wilt openen, kunt u de aanwijzing use namespace vermijden door de naam van de methode of eigenschap met de naamruimte en het naamkwalificatieteken te kwalificeren. Met de volgende code wordt bijvoorbeeld getoond hoe u de naam myFunction() met de naamruimte example1 kunt kwalificeren:
example1::myFunction();
Naamruimten gebruiken
U vindt een praktijkvoorbeeld van een naamruimte die wordt gebruikt om naamconflicten te voorkomen in de klasse flash.utils.Proxy die deel uitmaakt van ActionScript 3.0. Met de klasse Proxy, die de vervanging is van de eigenschap Object.__resolve eigenschap in ActionScript 2.0, waarmee u verwijzingen naar niet-gedefinieerde eigenschappen of methoden onderscheppen voordat een fout optreedt. Alle methoden van de klasse Proxy bevinden zich in de naamruimte flash_proxy om naamconflicten te voorkomen.
Voor een beter begrip van hoe de naamruimte flash_proxy wordt gebruikt, moet u weten hoe u de klasse Proxy gebruikt. De functionaliteit van de klasse Proxy is alleen beschikbaar voor klassen die ervan overerven. Met andere woorden, als u de methoden van de klasse Proxy voor een ander object wilt gebruiken, moet de klassendefinitie van het object de klasse Proxy uitbreiden. Als u bijvoorbeeld pogingen om een ongedefinieerde methode aan te roepen wilt onderscheppen, breidt u de klasse Proxy uit en overschrijft u vervolgens de methode callProperty() van de klasse Proxy.
Zoals eerder is besproken, bestaat het implementeren van naamruimten doorgaans uit drie stappen: definiëren, toepassen en ernaar verwijzen. Omdat u de methoden van de klasse Proxy echter nooit expliciet aanroept, wordt de naamruimte flash_proxy alleen gedefinieerd en toegepast, maar wordt er niet naar verwezen. ActionScript 3.0 definieert de naamruimte flash_proxy en past deze toe in de klasse Proxy. De code hoeft de naamruimte flash_proxy alleen toe te passen op klassen die de klasse Proxy uitbreiden.
De naamruimte flash_proxy wordt ongeveer als volgt gedefinieerd in het pakket flash.utils:
package flash.utils
{
public namespace flash_proxy;
}
De naamruimte wordt toegepast op de methoden van de klasse Proxy zoals in het volgende fragment van de klasse Proxy wordt getoond:
public class Proxy
{
flash_proxy function callProperty(name:*, ... rest):*
flash_proxy function deleteProperty(name:*):Boolean
...
}
Zoals de volgende code laat zien, moet u eerst de klasse Proxy en de naamruimte flash_proxy importeren. Vervolgens moet u de klasse zo declareren dat deze de klasse Proxy uitbreidt (u moet ook het attribuut dynamic toevoegen als u in de strikte modus compileert). Wanneer u de methode callProperty() overschrijft, moet u de naamruimte flash_proxy gebruiken.
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);
}
}
}
Als u een instantie van de klasse MyProxy maakt en een ongedefinieerde methode aanroept, zoals de aangeroepen methode testing() in het volgende voorbeeld, onderschept het object Proxy de methodeaanroep en worden de instructies binnen de overschreven methode callProperty() uitgevoerd (in dit geval een eenvoudige instructie trace()).
var mySample:MyProxy = new MyProxy();
mySample.testing(); // method call intercepted: testing
Er zijn twee voordelen verbonden aan het opnemen van de klasse Proxy binnen de naamruimte flash_proxy. Ten eerste vermindert een aparte naamruimte de hoeveelheid rommelige code in de openbare interface van de klassen die de klasse Proxy uitbreiden. (Er zijn meer dan tien methoden in de klasse Proxy die u kunt overschrijven en die u niet rechtstreeks kunt aanroepen. Het plaatsen van al deze methoden in de naamruimte public zou tot verwarring kunnen leiden.) Ten tweede voorkomt het gebruik van de naamruimte flash_proxy naamconflicten in het geval dat de subklasse Proxy instantiemethoden bevat met namen die overeenkomen met een van de methoden van de klasse Proxy. U wilt bijvoorbeeld een van uw eigen methoden callProperty() noemen. De volgende code is acceptabel, omdat uw versie van de methode callProperty() zich in een andere naamruimte bevindt:
dynamic class MyProxy extends Proxy
{
public function callProperty() {}
flash_proxy override function callProperty(name:*, ...rest):*
{
trace("method call intercepted: " + name);
}
}
Naamruimten kunnen ook nuttig zijn wanneer u voor toegang wilt zorgen tot methoden of eigenschappen op een manier die niet mogelijk is met de vier toegangsbeheerspecificaties (public, private, internal en protected). U hebt bijvoorbeeld enkele hulpprogrammamethoden verspreid over diverse pakketten. U wilt deze methoden beschikbaar maken voor alle pakketten, maar ze niet als public declareren. U kunt voor dit doel een naamruimte maken en gebruiken als uw eigen speciale toegangsbeheerspecificatie.
In het volgende voorbeeld wordt een door de gebruiker gedefinieerde naamruimte gebruikt om twee functies in verschillende pakketten te groeperen. Door de twee functies in dezelfde naamruimte te groeperen, kunt u ze beide zichtbaar maken voor een klasse of pakket met behulp van een instructie use namespace.
In dit voorbeeld worden vier bestanden gebruikt om deze techniek te demonstreren. Al deze bestanden moeten in uw klassenpad zijn opgenomen. Met het eerste bestand, myInternal.as, wordt de naamruimte myInternal gedefinieerd. Het bestand bevindt zich in een pakket met de naam example, zodat u het bestand in een map met de naam example moet plaatsen. De naamruimte is gemarkeerd als public, zodat deze in andere pakketten kan worden geïmporteerd.
// myInternal.as in folder example
package example
{
public namespace myInternal = "http://www.adobe.com/2006/actionscript/examples";
}
Het tweede en derde bestand, Utility.as en Helper.as, definiëren de klassen met de methoden die beschikbaar moeten zijn voor andere pakketten. De klasse Utility bevindt zich in het pakket example.alpha. Dit betekent dat het bestand in een map moet worden geplaatst met de naam alpha die een submap is van de map example. De klasse Helper bevindt zich in het pakket example.beta. Dit betekent dat het bestand in een map moet worden geplaatst met de naam beta die eveneens een submap is van de map example. Beide pakketten, example.alpha en example.beta, moeten de naamruimte importeren voordat deze wordt gebruikt.
// 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;
}
}
}
Het vierde bestand, NamespaceUseCase.as, is de hoofdtoepassingsklasse en moet op hetzelfde niveau zijn als de map example. In Flash Professional zou deze klasse worden gebruikt als de documentklasse voor het FLA-bestand. De klasse NamespaceUseCase importeert bovendien de naamruimte myInternal en gebruikt deze om de twee statische methoden op te roepen die zich in de andere pakketten bevinden. In het voorbeeld worden alleen statische methoden gebruikt om de code eenvoudig te houden. U kunt zowel statische methoden als instantiemethoden in de naamruimte myInternal plaatsen.
// 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]
}
}
}