Med namnutrymmen får du kontroll över hur egenskaper och metoder du skapar visas. Tänk på åtkomstkontrollsspecifikationerna public, private, protected och internal som inbyggda namnutrymmen. Om dessa fördefinierade specifikationer inte passar kan du skapa egna namnutrymmen.
Om du känner till XML-namnutrymmen är mycket av den här beskrivningen inte ny för dig, även om syntax och detaljer i ActionScript-implementeringen är litet annorlunda än i XML. Även om du inte har arbetat med namnutrymmen tidigare förstår du ändå själva begreppet, men implementeringen har en speciell terminologi som du måste lära dig.
Om du vill förstå hur namnutrymmen fungerar kan det vara bra att veta att namnet på en egenskap eller en metod består av två delar: en identifierare och ett namnutrymme. Identifieraren är det som du vanligtvis tänker på som ett namn. Identifieraren i följande klassdefinition är sampleGreeting och sampleFunction():
class SampleCode
{
var sampleGreeting:String;
function sampleFunction () {
trace(sampleGreeting + " from sampleFunction()");
}
}
När definitioner föregås av ett namnutrymmesattribut är deras namn kvalificerat av standardnamnutrymmet internal, vilket betyder att de bara visas för anropare i samma paket. Om kompilatorn är inställd på strikt läge utfärdas en varning om att namnutrymmet internal tillämpas på alla identifierare som saknar ett namnutrymmesattribut. Om du vill vara säker på att en identifierare ska bli tillgänglig överallt, måste du lägga in attributet public före identifierarnamnet. I föregående exempelkod har både sampleGreeting och sampleFunction() namnutrymmesvärdet internal.
Du följer tre grundprinciper när du använder namnutrymmen. För det första måste du definiera namnutrymmet med nyckelordet namespace. I följande kod definieras till exempel namnutrymmet version1:
namespace version1;
För det andra använder du namnutrymmet i stället för en åtkomstkontrollsspecifikation i en egenskaps- eller metoddeklaration. I följande exempel placeras funktionen myFunction() i namnutrymmet version1:
version1 function myFunction() {}
För det tredje kan du, när du har tillämpat namnutrymmet, referera det med direktivet use eller genom att kvalificera namnet på en identifierare med ett namnutrymme. I följande exempel refereras funktionen myFunction() via direktivet use:
use namespace version1;
myFunction();
Du kan också använda ett kvalificerat namn för att referera funktionen myFunction(), vilket visas i följande exempel:
version1::myFunction();
Definiera namnutrymmen
Namnutrymmen innehåller ett värde, URI (Uniform Resource Identifier), som ibland kallas namnutrymmesnamn. Med en URI kan du kontrollera att namnutrymmesdefinitionen är unik.
Du skapar ett namnutrymme genom att deklarera en namnutrymmesdefinition på ett av två sätt. Du kan antingen definiera namnutrymmet med en angiven URI, på samma sätt som du definierar ett XML-namnutrymme, eller också kan du utelämna detta URI. I följande exempel visas hur du definierar ett namnutrymme med en URI:
namespace flash_proxy = "http://www.adobe.com/flash/proxy";
URI:n fungerar som en unik identifikationssträng för namnutrymmet. Om du, som i följande exempel, utelämnar URI:n skapar kompilatorn en unik intern identifikationssträng i stället för URI:n. Du har inte åtkomst till den här interna identifikationsfilen.
namespace flash_proxy;
När du har definierat ett namnutrymme, med eller utan en URI, kan namnutrymmet inte definieras om i samma omfång. Om du försöker definiera ett namnutrymme som tidigare har definierats i samma omfång genereras ett kompilatorfel.
Om ett namnutrymme definieras inuti ett paket eller en klass, visas det bara för kod utanför paketet eller klassen om lämplig åtkomstkontrollsspecifikation används. Följande kod visar namnutrymmet flash_proxy som definierats inuti paketet flash.utils. I följande exempel betyder avsaknaden av en åtkomstkontrollsspecifikation att namnutrymmet flash_proxy bara visas för kod inuti paketet flash.utils och inte för kod utanför paketet:
package flash.utils
{
namespace flash_proxy;
}
I följande kod används attributet public för att visa namnutrymmet flash_proxy för kod utanför paketet:
package flash.utils
{
public namespace flash_proxy;
}
Använda namnutrymmen
Att använda ett namnutrymme innebär att placera en definition i ett namnutrymme. Definitioner, som funktioner, variabler och konstanter, kan placeras i namnutrymmen (du kan inte placera en klass i ett anpassat namnutrymme).
En funktion kan till exempel deklareras med hjälp av åtkomstkontrollsspecifikationen public. Om du använder attributet public i en funktionsdefinition placeras funktionen i det allmänna namnutrymmet, vilket gör att funktionen blir tillgänglig för all kod. När du har definierat ett namnutrymme kan du använda namnutrymmet på samma sätt som du använder attributet public, och definitionen blir tillgänglig för kod som kan referera till ditt anpassade namnutrymme. Om du till exempel definierar namnutrymmet example1 kan du lägga till metoden myFunction() och använda example1 som ett attribut, vilket visas i följande exempel:
namespace example1;
class someClass
{
example1 myFunction() {}
}
Att deklarera metoden myFunction() och använda namnutrymmet example1 som ett attribut betyder att metoden hör till namnutrymmet example1.
Du måste tänka på följande när du använder namnutrymmen:
Du kan bara använda ett namnutrymme för varje deklaration.
Du kan inte använda ett namnutrymmesattribut för mer än en definition i taget. Om du vill använda namnutrymmet på tio olika funktioner måste du alltså lägga till namnutrymmet som ett attribut i alla tio funktionsdefinitionerna.
Om du använder ett namnutrymme kan du inte ange en åtkomstkontrollsspecifikation samtidigt, eftersom namnutrymmen och åtkomstkontrollsspecifikationer inte kan kombineras. Du kan alltså inte deklarera en funktion eller en egenskap som public, private, protected eller internal när du samtidigt använder namnutrymmet.
Referera namnutrymmen
Du behöver inte explicit referera ett namnutrymme när du använder en metod eller en egenskap som deklarerats med någon av åtkomstkontrollsnamnutrymmena, till exempel public, private, protected och internal. Detta beror på att åtkomsten till dessa speciella namnutrymmen styrs av sammanhanget. Definitioner som placerats i namnutrymmet private blir till exempel automatiskt tillgängliga för kod i samma klass. Det finns däremot ingen sådan sammanhangskänslighet för de namnutrymmen du definierar. Om du vill använda en metod eller egenskap som du har placerat i ett anpassat namnutrymme, måste du referera till namnutrymmet.
Du kan referera namnutrymmen med direktivet use namespace och du kan kvalificera namnet med namnutrymmet med hjälp av namnkvalificeringstecknet (::). Om du refererar ett namnutrymme med direktivet use namespace ”öppnas” namnutrymmet, så att det kan användas på alla identifierare som inte är kvalificerade. Om du har definierat namnutrymmet example1 kan du öppna namnet i namnutrymmet genom att använda use namespace example1:
use namespace example1;
myFunction();
Du kan öppna flera namnutrymmen samtidigt. När du har öppnat ett namnutrymme med use namespace förblir det öppet i hela kodblocket som det öppnats i. Det finns inget sätt att explicit stänga ett namnutrymme.
Om du har flera öppna namnutrymmen ökar emellertid risken för namnkonflikter. Om du föredrar att inte öppna ett namnutrymme, kan du undvika direktivet use namespace genom att kvalificera metod- eller egenskapsnamnet med namnutrymmet och namnkvalificeringstecknet. I följande kod visas hur du kan kvalificera namnet myFunction() med namnutrymmet example1:
example1::myFunction();
Använda namnutrymmen
Du hittar ett verkligt exempel på ett namnutrymme som används för att förhindra namnkonflikter i klassen flash.utils.Proxy som ingår i ActionScript 3.0. Klassen Proxy ersätter egenskapen Object.__resolve från ActionScript 2.0, gör att du kan avbryta referenser till odefinierade egenskaper eller metoder innan ett fel inträffar. Alla metoder för klassen Proxy finns i namnutrymmet flash_proxy för att förhindra namnkonflikter.
För att du bättre ska kunna förstå hur namnutrymmet flash_proxy används, måste du förstå hur klassen Proxy ska användas. Klassen Proxys funktioner är bara tillgängliga för klasser som ärver från denna klass. Om du vill använda metoderna i klassen Proxy på ett objekt, måste objektets klassdefinition utöka klassen Proxy. Om du till exempel vill avbryta försök till anrop av en odefinierad metod, utökar du klassen Proxy och sedan åsidosätter du metoden callProperty() i klassen Proxy.
Du kanske kommer ihåg att implementering av namnutrymmen vanligtvis är en trestegsprocess som består av att definiera, använda och referera ett namnutrymme. Eftersom du aldrig explicit anropar någon av klassen Proxys metoder, kommer namnutrymmet flash_proxy att definieras och användas, men inte att refereras. ActionScript 3.0 definierar namnutrymmet flash_proxy och använder det i klassen Proxy. Din kod behöver bara använda namnutrymmet flash_proxy på klasser som utökar klassen Proxy.
Namnutrymmet flash_proxy definieras i paketet flash.utils på ett sätt som liknar detta:
package flash.utils
{
public namespace flash_proxy;
}
Namnutrymmet används på metoderna i klassen Proxy enligt följande utdrag ur klassen Proxy:
public class Proxy
{
flash_proxy function callProperty(name:*, ... rest):*
flash_proxy function deleteProperty(name:*):Boolean
...
}
Som följande kod visar måste du först importera både klassen Proxy och namnutrymmet flash_proxy. Du måste deklarera klassen så att den utökar klassen Proxy (du måste alltså lägga till attributet dynamic om du kompilerar i strikt läge). När du åsidosätter metoden callProperty() måste du använda namnutrymmet flash_property.
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);
}
}
}
Om du skapar en instans av klassen MyProxy och anropar en odefinierad metod, till exempel metoden testing(), som anropas i följande exempel, kommer objektet Proxy att avbryta metodanropet och köra programsatserna inuti den åsidosatta metoden callProperty() (i det här fallet en enkel trace()-programsats).
var mySample:MyProxy = new MyProxy();
mySample.testing(); // method call intercepted: testing
Det finns två fördelar med att ha metoder av klassen Proxy inuti namnutrymmet flash_proxy. Om du för det första har ett separat namnutrymme minskas skräpet i det gemensamma gränssnittet för en klass som utökar klassen Proxy. (Det finns ungefär ett dussin metoder i klassen Proxy som du kan åsidosätta, och ingen av dem kan anropas direkt. Om du placerar dem i det allmänna namnutrymmet blir det konstigt.) Om du för det andra använder namnutrymmet flash_proxy undviker du namnkonflikter om underklassen till Proxy innehåller instansmetoder med samma namn som någon av metoderna i klassen Proxy. Du kan till exempel vilja kalla en av dina metoder callProperty(). Följande kod godkänns eftersom din version av metoden callProperty() finns i ett annat namnutrymme:
dynamic class MyProxy extends Proxy
{
public function callProperty() {}
flash_proxy override function callProperty(name:*, ...rest):*
{
trace("method call intercepted: " + name);
}
}
Det kan också vara bra att använda namnutrymmen när du vill ha åtkomst till metoder och egenskaper på ett sätt som inte kan uppnås med de fyra åtkomstkontrollsspecifikationerna (public, private, internal och protected). Det finns till exempel några verktygsfunktioner som är spridda över flera paket. Du vill att alla dessa metoder ska vara tillgängliga för alla dina paket, men du vill inte att metoderna ska vara allmänna. För att uppnå detta kan du skapa ett namnutrymme och använda det som en egen speciell åtkomstkontrollsspecifikation.
I följande exempel används ett användardefinierat namnutrymme för att gruppera två funktioner som finns i olika paket. Genom att gruppera dem i samma namnutrymme, kan du göra båda funktionerna synliga för en klass eller ett paket via en enda use namespace-programsats.
I det här exemplet används fyra filer för att visa den här tekniken. Alla filerna måste ligga i din klassökväg. Den första filen, myInternal.as, används för att definiera namnutrymmet myInternal. Eftersom filen finns i ett paket som heter example, måste du placera filen i en mapp som heter example. Namnutrymmet markeras som public så att det kan importeras till andra paket.
// myInternal.as in folder example
package example
{
public namespace myInternal = "http://www.adobe.com/2006/actionscript/examples";
}
Den andra och tredje filen, Utility.as och Helper.as, definierar de klasser som innehåller metoder som ska vara tillgängliga för andra paket. Klassen Utility finns i paketet example.alpha, vilket betyder att filen ska placeras i en mapp som heter alpha som är en undermapp till mappen example. Klassen Helper finns i paketet example.beta, vilket betyder att filen ska placeras i en mapp som heter beta som också är en undermapp till mappen example. Båda dessa paket, example.alpha och example.beta, måste importera namnutrymmet innan de kan använda det.
// 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;
}
}
}
Den fjärde filen, NamespaceUseCase.as, är huvudprogramklassen och ska ligga på samma nivå som mappen example. I Flash Professional används den här klassen som dokumentklass för FLA. Klassen NamespaceUseCase importerar också namnutrymmet myInternal och använder det för att anropa de två statiska metoderna som finns i andra paket. I exemplet används statiska metoder bara för att förenkla koden. Både statiska metoder och instansmetoder kan placeras i namnutrymmet 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]
}
}
}