Pakiety i przestrzenie nazw

Pakiety i przestrzenie nazw to pojęcia pokrewne. Pakiety umożliwiają powiązanie definicji klas w sposób usprawniający współużytkowanie kodu i minimalizujący konflikty nazw. Przestrzenie nazw umożliwiają sterowanie widocznością identyfikatorów, np. nazw właściwości i metod, i mogą być stosowane w kodzie niezależnie od tego, czy znajduje się on w pakiecie, czy poza pakietem. Pakiety pozwalają na porządkowanie plików klas, a przestrzenie nazw służą do zarządzania widocznością poszczególnych właściwości i metod.

Opisy pakietów

Pakiety w języku ActionScript 3.0 są implementowane przy użyciu przestrzeni nazw, ale nie są z nimi tożsame. Deklaracja pakietu powoduje niejawne utworzenie specjalnego typu przestrzeni nazw, który na pewno będzie znany w czasie kompilacji. Przestrzenie nazw utworzone jawnie nie zawsze są znane w czasie kompilacji.

W poniższym przykładzie zastosowano dyrektywę package do utworzenia prostego pakietu zawierającego jedną klasę:

package samples 
{ 
    public class SampleCode 
    { 
        public var sampleGreeting:String; 
        public function sampleFunction() 
        { 
            trace(sampleGreeting + " from sampleFunction()"); 
        } 
    } 
}

Nazwa klasy w tym przykładzie to SampleCode. Ponieważ klasa znajduje się w pakiecie samples, kompilator automatycznie kwalifikuje nazwę klasy w czasie kompilacji, przekształcając ją do pełnej postaci: samples.SampleCode. Ponadto kompilator kwalifikuje nazwy wszelkich właściwości lub metod, a zatem sampleGreeting i sampleFunction() staną się odpowiednio nazwami kwalifikowanymi samples.SampleCode.sampleGreeting i samples.SampleCode.sampleFunction() .

Wielu programistów, zwłaszcza z doświadczeniem w języku Java, preferuje umieszczanie na najwyższym poziomie pakietu wyłącznie klas. Jednak w języku ActionScript 3.0 na najwyższym poziomie pakietu mogą znajdować się nie tylko klasy, lecz także zmienne, funkcje, a nawet instrukcje. Jednym z zaawansowanych zastosowań tej funkcji jest zdefiniowanie przestrzeni nazw na najwyższym poziomie pakietu, tak aby była ona dostępna dla wszystkich klas w tym pakiecie. Tylko dwa specyfikatory dostępu — public i internal — są dozwolone na najwyższym poziomie pakietu. W przeciwieństwie do języka Java, który dopuszcza deklarowanie klas zagnieżdżonych jako klas prywatnych, język ActionScript 3.0 nie obsługuje ani klas zagnieżdżonych, ani prywatnych.

Jednak pod wieloma innymi względami pakiety języka ActionScript 3.0 są podobne do pakietów w języku programowania Java. Jak widzimy w poprzednim przykładzie, w pełni kwalifikowane odniesienia do pakietu zapisuje się przy użyciu operatora kropki ( . ), podobnie jak w języku Java. Pakietów można użyć do zorganizowania kodu w intuicyjną strukturę hierarchiczną, z której będą mogli korzystać inni programiści. Usprawnia to współużytkowanie kodu, ponieważ każdy programista może utworzyć własne pakiety udostępnione następnie innym, a także używać we własnym kodzie pakietów utworzonych przez innych programistów.

Zastosowanie pakietów pomaga także w zapewnieniu unikalności używanych nazw i wyeliminowaniu ich konfliktów z innymi nazwami (identyfikatorami). W istocie wiele osób właśnie to zastosowanie postrzega jako najważniejszą zaletę pakietów. Załóżmy, że dwóch programistów, którzy chcą używać nawzajem swoich fragmentów kodu, utworzyło klasy o nazwie SampleCode. Bez pakietów powstałby konflikt nazw, a jedynym rozwiązaniem byłaby zmiana nazwy jednej z klas. Jednak dzięki pakietom można w prosty sposób uniknąć konfliktu nazw, umieszczając każdą z klas w osobnym pakiecie (lub co najmniej jedną z klas w osobnym pakiecie). Wystarczy, że pakiety będą miały różne nazwy.

Dozwolone jest również umieszczanie kropek w nazwach pakietów w celu tworzenia pakietów zagnieżdżonych. Pozwala to na stworzenie hierarchicznej struktury pakietów. Dobrym przykładem jest pakiet flash.display dostępny w języku ActionScript 3.0. Pakiet flash.display jest zagnieżdżony w pakiecie flash.

Większa część języka ActionScript 3.0 jest zorganizowana w pakiecie flash. Na przykład pakiet flash.display zawiera interfejs API listy wyświetlania, a pakiet flash.events zawiera nowy model zdarzeń.

Tworzenie pakietów

Język ActionScript 3.0 zapewnia dużą swobodę w organizowaniu pakietów, klas i plików źródłowych. W poprzednich wersjach języka ActionScript na jeden plik źródłowy mogła przypadać tylko jedna klasa, a nazwa pliku źródłowego musiała być identyczna z nazwą klasy. Język ActionScript 3.0 dopuszcza umieszczenie wielu klas w jednym pliku źródłowym, ale tylko jedna klasa w każdym pliku może być dostępna dla kodu zewnętrznego względem tego pliku. Innymi słowy, tylko jedna klasa w każdym pliku może być zadeklarowana wewnątrz deklaracji pakietu. Ewentualne dodatkowe klasy należy zadeklarować poza definicją pakietu, przez co staną się one niewidoczne dla kodu poza plikiem źródłowym. Nazwa klasy zadeklarowanej w definicji pakietu musi być identyczna z nazwą pliku źródłowego.

Język ActionScript 3.0 zapewnia także większą elastyczność w sposobie deklarowania pakietów. W poprzednich wersjach języka ActionScript pakiety odzwierciedlały po prostu katalogi zawierające pliki źródłowe i nie były deklarowane za pomocą instrukcji package ; zamiast tego nazwa pakietu była uwzględniana w pełni kwalifikowanej nazwie klasy w ramach deklaracji klasy. Mimo że w języku ActionScript 3.0 pakiety nadal odzwierciedlają katalogi, mogą teraz zawierać nie tylko klasy. W języku ActionScript 3.0 do deklarowania pakietów używana jest instrukcja package , co oznacza, że na najwyższym poziomie pakietu można także deklarować zmienne, funkcje i przestrzenie nazw. Dozwolone jest nawet umieszczanie instrukcji wykonywalnych na najwyższym poziomie pakietu. W przypadku zadeklarowania zmiennych, funkcji lub przestrzeni nazw na najwyższym poziomie pakietu jedynymi atrybutami dostępnymi na tym poziomie są public i internal , a ponadto tylko jedna deklaracja na poziomie pakietu w danym pliku może zawierać atrybut public , niezależnie od tego, czy jest to deklaracja klasy, zmiennej, funkcji, czy przestrzeni nazw.

Pakiety są użyteczne do organizowania kodu i zapobiegania konfliktom nazw. Nie należy mylić koncepcji pakietów z zupełnie odrębną koncepcją dziedziczenia klas. Dwie klasy rezydujące w tym samym pakiecie mają wspólną przestrzeń nazw, ale nie muszą być wcale powiązane ze sobą w żaden inny sposób. Podobnie, pakiet zagnieżdżony nie musi mieć relacji semantycznej ze swoim pakietem nadrzędnym.

Importowanie pakietów

Jeśli chcemy użyć klasy znajdującej się wewnątrz pakietu, musimy zaimportować albo cały pakiet, albo tę konkretną klasę. Jest to rozwiązanie różne od przyjętego w języku ActionScript 2.0, w którym importowanie klas było opcjonalne.

Przykład: weźmy pod uwagę klasę SampleCode przedstawioną poprzednio. Jeśli klasa rezyduje w pakiecie o nazwie samples, należy użyć jednej z poniższych instrukcji importu przed użyciem klasy SampleCode:

import samples.*;

lub

import samples.SampleCode;

Co do zasady instrukcje import powinny być maksymalnie precyzyjne. Jeśli planowane jest użycie tylko klasy SampleCode z pakietu samples, należy zaimportować tylko klasę SampleCode, a nie cały pakiet, do którego ona należy. Zaimportowanie całego pakietu może doprowadzić do nieoczekiwanych konfliktów nazw.

Ponadto konieczne jest umieszczenie kodu źródłowego definiującego pakiet lub klasę w ścieżce klas . Ścieżka klas jest to zdefiniowana przez użytkownika lista ścieżek do katalogów lokalnych, w których kompilator poszukuje importowanych pakietów i klas. Ścieżka klas jest czasami nazywana ścieżką budowania lub ścieżką źródłową .

Po prawidłowym zaimportowaniu klasy lub pakietu można używać w pełni kwalifikowanej nazwy klasy (samples.SampleCode) lub tylko nazwy klasy (SampleCode).

W pełni kwalifikowane nazwy są użyteczne, gdy identyczne nazwy klas, metod lub właściwości prowadziłyby do niejednoznaczoności w kodzie, jednak z drugiej strony używanie ich we wszystkich identyfikatorach może być uciążliwe. Na przykład zastosowanie w pełni kwalifikowanej nazwy prowadzi do niepotrzebnej rozwlekłości kodu tworzącego instancję klasy SampleCode:

var mySample:samples.SampleCode = new samples.SampleCode();

Im więcej poziomów zagnieżdżenia pakietów, tym mniej czytelny będzie kod. W sytuacjach, w których mamy pewność, że niejednoznaczne identyfikatory nie stanowią problemu, można poprawić czytelność kodu, stosując proste identyfikatory. Na przykład utworzenie nowego wystąpienia klasy SampleCode można zapisać znacznie krócej, używając samego identyfikatora klasy.

var mySample:SampleCode = new SampleCode();

Próba użycia nazw bez wcześniejszego zaimportowania odpowiedniego pakietu lub klasy spowoduje, że kompilator nie będzie mógł znaleźć definicji klas. Z drugiej strony po zaimportowaniu pakietu lub klasy każda próba zdefiniowania nazwy kolidującej z nazwą zaimportowaną spowoduje błąd.

Po utworzeniu pakietu domyślnym specyfikatorem dostępu wszystkich jego elementów jest specyfikator internal , co oznacza, że domyślnie elementy pakietu są widoczne tylko dla innych elementów tego samego pakietu. Aby klasa była dostępna dla kodu poza pakietem, należy ją zadeklarować jako public . Poniższy przykładowy pakiet zawiera dwie klasy: SampleCode i CodeFormatter:

// SampleCode.as file 
package samples 
{ 
    public class SampleCode {} 
} 
 
// CodeFormatter.as file 
package samples 
{ 
    class CodeFormatter {} 
}

Klasa SampleCode jest widoczna na zewnątrz pakietu, ponieważ jest zadeklarowana jako publiczna ( public ). Jednak klasa CodeFormatter jest widoczna tylko wewnątrz pakietu samples. Próba dostępu do klasy CodeFormatter poza pakietem samples spowoduje błąd, co ilustruje poniższy przykład:

import samples.SampleCode; 
import samples.CodeFormatter; 
var mySample:SampleCode = new SampleCode(); // okay, public class 
var myFormatter:CodeFormatter = new CodeFormatter(); // error

Aby obie klasy były dostępne na zewnątrz pakietu, należy zadeklarować obie jako publiczne ( public ). Nie jest dozwolone zastosowanie atrybutu public do deklaracji pakietu.

W pełni kwalifikowane nazwy są przydatne do eliminowania konfliktów nazw, jakie mogą wystąpić podczas korzystania z pakietów. Taka sytuacja może wystąpić np. w wypadku zaimportowania dwóch pakietów, które definiują klasy o tym samym identyfikatorze. Na przykład, rozważmy następujący pakiet, który także zawiera klasę o nazwie SampleCode:

package langref.samples 
{ 
    public class SampleCode {} 
}

Jeżeli zaimportujemy obie klasy, tak jak poniżej, to przy próbie użycia klasy SampleCode wystąpi konflikt nazw:

import samples.SampleCode; 
import langref.samples.SampleCode; 
var mySample:SampleCode = new SampleCode(); // name conflict

Kompilator nie wie, której klasy SampleCode ma użyć. Aby rozstrzygnąć ten konflikt, należy użyć w pełni kwalifikowanej nazwy każdej z klas:

var sample1:samples.SampleCode = new samples.SampleCode(); 
var sample2:langref.samples.SampleCode = new langref.samples.SampleCode();
Uwaga: Programiści z doświadczeniem w programowaniu w języku C++, często mylą instrukcję import z instrukcją #include . Dyrektywa #include jest potrzebna w języku C++, ponieważ kompilatory C++ przetwarzają po jednym pliku naraz i nie odczytują definicji klas z innych plików, o ile ich nagłówki nie zostaną jawnie włączone do bieżącego pliku. W języku ActionScript 3.0 występuje dyrektywa include , jednak nie służy ona do importowania klas ani pakietów. Do importowania klas lub pakietów w języku ActionScript 3.0 należy używać instrukcji import , a w ścieżce klas należy umieścić plik źródłowy zawierający pakiet.

Przestrzenie nazw

Przestrzenie nazw zapewniają kontrolę nad widocznością właściwości i metod tworzonych przez programistę. Specyfikatory dostępu public , private , protected, i internal można potraktować w istocie jako wbudowane przestrzenie nazw. Jeśli te predefiniowane specyfikatory dostępu nie odpowiadają potrzebom w danym programie, można utworzyć własne przestrzenie nazw.

Dla czytelników, którym nieobca jest koncepcja przestrzeni nazw w języku XML, większość z poniższego omówienia będzie zawierać informacje już znane, z tym że składnia i szczegóły implementacji w języku ActionScript nieznacznie różnią się od specyfikacji języka XML. Jeśli czytelnik nie pracował jeszcze z przestrzeniami nazw, zrozumienie samej koncepcji nie powinno nastręczać problemów, konieczne jest natomiast zapoznanie się z charakterystyczną terminologią używaną w tej implementacji języka.

Aby zrozumieć koncepcję przestrzeni nazw, warto uświadomić sobie, że nazwa właściwości lub metody zawsze składa się z dwóch części: identyfikatora i przestrzeni nazw. Identyfikator jest tą częścią, którą intuicyjnie postrzegamy jako nazwę. Na przykład identyfikatorami w poniższej definicji klasy są sampleGreeting oraz sampleFunction() :

class SampleCode 
{ 
    var sampleGreeting:String; 
    function sampleFunction () { 
        trace(sampleGreeting + " from sampleFunction()"); 
    } 
}

Gdy definicja nie jest poprzedzona atrybutem namespace, definiowana nazwa jest kwalifikowana domyślną przestrzenią nazw internal , co oznacza, że jest widoczna tylko dla kodu wywołującego w tym samym pakiecie. W trybie ścisłym kompilator generuje ostrzeżenie mówiące, że przestrzeń nazw internal obowiązuje dla wszystkich identyfikatorów bez atrybutu namespace. Aby sprawić, że identyfikator będzie dostępny wszędzie, należy jawnie poprzedzić jego nazwę atrybutem public . W poprzednim przykładowym kodzie zarówno identyfikator sampleGreeting , jak i identyfikator sampleFunction() należą do przestrzeni nazw internal .

Korzystając z przestrzeni nazw, programista wykonuje trzy podstawowe kroki. Najpierw należy zdefiniować przestrzeń nazw, używając słowa kluczowego namespace . Na przykład w poniższym kodzie zdefiniowano przestrzeń nazw version1 :

namespace version1;

Następnie należy zastosować przestrzeń nazw, podając jej nazwę zamiast specyfikatora dostępu w deklaracji właściwości lub metody. W poniższym przykładzie funkcja o nazwie myFunction() została umieszczona w przestrzeni nazw version1 :

version1 function myFunction() {}

Po trzecie, już po zastosowaniu przestrzeni nazw, można odwoływać się do niej za pomocą dyrektywy use lub poprzez kwalifikację identyfikatora nazwą przestrzeni nazw. W poniższym przykładzie występuje odwołanie do funkcji myFunction() przy użyciu dyrektywy use :

use namespace version1; 
myFunction();

Do funkcji myFunction() można się też odwoływać za pomocą nazwy kwalifikowanej, co ilustruje poniższy przykład:

version1::myFunction();

Definiowanie przestrzeni nazw

Każda przestrzeń nazw zawiera jedną wartość, tzw. identyfikator URI (ang. Uniform Resource Identifier), który jest czasami nazywany nazwą przestrzeni nazw . Identyfikator URI zapewnia unikalność definicji przestrzeni nazw.

Przestrzeń nazw można utworzyć, deklarując jej definicję na jeden z dwóch sposobów. Przestrzeń nazw można zdefiniować, podając jawnie identyfikator URI (tak jak przy definiowaniu przestrzeni nazw XML), lub nie podając identyfikatora URI. Poniższy przykład ilustruje definiowanie przestrzeni nazw przy użyciu identyfikatora URI:

namespace flash_proxy = "http://www.adobe.com/flash/proxy";

URI jest ciągiem znaków jednoznacznie identyfikującym daną przestrzeń nazw. W wypadku pominięcia identyfikatora URI, tak jak w poniższym przykładzie, kompilator tworzy w jego miejsce unikalny wewnętrzny ciąg identyfikacyjny. Programista nie ma dostępu do tego wewnętrznego ciągu znaków.

namespace flash_proxy;

Raz zdefiniowanej przestrzeni nazw — z użyciem lub bez użycia identyfikatora URI — nie można ponownie zdefiniować w tym samym zasięgu. Próba zdefiniowania przestrzeni nazw, która została już wcześniej zdefiniowana w tym samym zasięgu, spowoduje błąd kompilatora.

Przestrzeń nazw zdefiniowana w pakiecie lub klasie może być niewidoczna dla kodu poza tym pakietem lub klasą, o ile nie zostanie użyty odpowiedni specyfikator dostępu. Poniższy przykładowy kod przedstawia definicję przestrzeni nazw flash_proxy wewnątrz pakietu flash.utils. W przykładzie tym brak specyfikatora dostępu oznacza, że klasa flash_proxy będzie widoczna tylko dla kodu w pakiecie flash.utils i że będzie niewidoczna dla kodu poza pakietem:

package flash.utils 
{ 
    namespace flash_proxy; 
}

W poniższym kodzie użyto atrybutu public , aby przestrzeń nazw flash_proxy była widoczna dla kodu poza pakietem:

package flash.utils 
{ 
    public namespace flash_proxy; 
}

Stosowanie przestrzeni nazw

Zastosowanie przestrzeni nazw polega na umieszczeniu definicji w tej przestrzeni. W przestrzeniach nazw można umieszczać funkcje, zmienne i stałe (nie można umieścić klasy w niestandardowej przestrzeni nazw).

Rozważmy na przykład funkcję zadeklarowaną przy użyciu specyfikatora dostępu (przestrzeni nazw) public . Użycie atrybutu public w definicji funkcji powoduje umieszczenie tej funkcji w publicznej przestrzeni nazw, przez co staje się ona dostępna dla całego kodu. Po zdefiniowaniu niestandardowej przestrzeni nazw można używać jej w taki sam sposób, jak atrybutu public , co spowoduje, że definicje będą dostępne dla kodu, który może odwoływać się do niestandardowej przestrzeni nazw. Na przykład, jeśli zdefiniujemy przestrzeń nazw example1 , możemy dodać metodę myFunction() z atrybutem example1 , co ilustruje poniższy przykład:

namespace example1; 
class someClass 
{ 
    example1 myFunction() {} 
}

Zadeklarowanie metody myFunction() przy użyciu przestrzeni nazw example1 jako atrybutu oznacza, że metoda ta będzie należała do przestrzeni nazw example1 .

Stosując przestrzenie nazw, należy pamiętać o następujących uwarunkowaniach:

  • Do każdej deklaracji można zastosować tylko jedną przestrzeń nazw.

  • Nie ma możliwości zastosowania atrybutu przestrzeni nazw do więcej niż jednej definicji naraz. Innymi słowy, jeśli chcemy zastosować własną przestrzeń nazw do dziesięciu różnych funkcji, należy dodać tę przestrzeń nazw jako atrybut do definicji każdej z tych funkcji.

  • Zastosowanie przestrzeni nazw wyklucza jednoczesne zastosowanie specyfikatora dostępu. Innymi słowy, nie można zadeklarować funkcji lub właściwości z atrybutem public , private , protected, lub internal i dodatkowo zastosować własnej przestrzeni nazw.

Odwołania do przestrzeni nazw

Nie jest konieczne jawne odwoływanie się do przestrzeni nazw, gdy używamy metod lub właściwości zadeklarowanych za pomocą dowolnego ze specyfikatorów dostępu, np. public , private , protected lub internal . Wynika to z faktu, że dostęp do przestrzeni nazw identyfikowanych przez te specyfikatory odbywa się na podstawie kontekstu. Na przykład definicje umieszczone w przestrzeni nazw private będą automatycznie dostępne dla kodu w tej samej klasie. Jednak w przypadku przestrzeni nazw zdefiniowanych przez użytkownika dostępność nie jest zależna od kontekstu. Aby użyć metody lub właściwości umieszczonej w niestandardowej przestrzeni nazw, należy odwołać się do tej przestrzeni.

Do przestrzeni nazw można się odwołać za pomocą dyrektywy use namespace lub kwalifikując nazwę przestrzeni nazw za pomocą operatora :: . Odwołanie za pomocą dyrektywy use namespace „otwiera” przestrzeń nazw, tak że zaczyna ona obowiązywać dla wszystkich identyfikatorów niekwalifikowanych. Na przykład, jeśli została zdefiniowana przestrzeń nazw example1 , można uzyskiwać dostęp do nazw w tej przestrzeni po wydaniu dyrektywy use namespace example1 :

use namespace example1; 
myFunction();

Możliwe jest otwarcie więcej niż jednej przestrzeni nazw w danej chwili. Przestrzeń nazw otwarta za pomocą dyrektywy use namespace pozostaje otwarta do końca bloku kodu zawierającego tę dyrektywę. Nie ma możliwości jawnego zamknięcia przestrzeni nazw.

Jednak otwarcie więcej niż jednej przestrzeni nazw naraz zwiększa prawdopodobieństwo konfliktów nazw. Aby uniknąć otwierania przestrzeni nazw za pomocą dyrektywy use namespace , można kwalifikować nazwy metod lub właściwości za pomocą nazwy przestrzeni nazw i operatora ::. Poniższy przykładowy kod ilustruje kwalifikowanie nazwy myFunction() przestrzenią nazw example1 :

example1::myFunction();

Korzystanie z przestrzeni nazw

W klasie flash.utils.Proxy, która jest częścią języka ActionScript 3.0, można znaleźć rzeczywiste przestrzenie nazw użyte w celu zapobieżenia konfliktom nazw. Klasa Proxy, która zastępuje właściwość Object.__resolve występującą w języku ActionScript 2.0, umożliwia przechwytywanie odwołań do niezdefiniowanych właściwości lub metod zanim takie odwołanie spowoduje błąd. Wszystkie metody klasy Proxy rezydują w przestrzeni nazw flash_proxy , co zapobiega konfliktom nazw.

Aby lepiej zrozumieć sposób wykorzystania przestrzeni nazw flash_proxy , należy zapoznać się z zasadami korzystania z klasy Proxy. Funkcjonalność klasy Proxy jest dostępna tylko dla klas, które z niej dziedziczą. Innymi słowy, aby można było używać metod klasy Proxy w obiekcie, klasa tego obiektu musi rozszerzać klasę Proxy. Na przykład, jeśli chcemy przechwytywać próby wywołania niezdefiniowanej metody, należałoby rozszerzyć klasę Proxy, a następnie przesłonić metodę callProperty() tej klasy.

Jak pamiętamy, implementacja przestrzeni nazw przebiega zazwyczaj w trzech krokach i polega na zdefiniowaniu, zastosowaniu przestrzeni nazw i odwołaniu się do niej. Ponieważ jednak metody klasy Proxy nigdy nie są wywoływane jawnie, przestrzeń nazw flash_proxy jest zdefiniowana i zastosowana, ale kod nigdy się do niej nie odwołuje. Język ActionScript 3.0 definiuje przestrzeń nazw flash_proxy i stosuje ją w klasie Proxy. Kod użytkownika musi stosować przestrzeń nazw flash_proxy tylko do klas rozszerzających klasę Proxy.

Przestrzeń nazw flash_proxy jest zdefiniowana w pakiecie flash.utils w sposób podobny do przedstawionego poniżej:

package flash.utils 
{ 
    public namespace flash_proxy; 
}

Przestrzeń nazw jest stosowana do metod klasy Proxy tak, jak ilustruje to poniższy fragment tej klasy:

public class Proxy 
{ 
    flash_proxy function callProperty(name:*, ... rest):* 
    flash_proxy function deleteProperty(name:*):Boolean 
    ... 
}

Tak jak przedstawiono to w poniższym przykładzie, należy najpierw zaimportować zarówno klasę Proxy, jak i przestrzeń nazw flash_proxy . Następnie należy zadeklarować własną klasę tak, aby rozszerzała ona klasę Proxy (należy także dodać atrybut dynamic , jeśli kompilacja odbywa się w trybie ścisłym). Przesłaniając metodę callProperty() , należy użyć przestrzeni nazw 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); 
        } 
    } 
}

W wypadku utworzenia instancji klasy MyProxy i wywołania metody niezdefiniowanej, jak metoda testing() wywoływana w poniższym przykładzie, obiekt Proxy przechwyci wywołanie metody i wykona instrukcje wewnątrz przesłoniętej metody callProperty() (w tym przypadku jest to prosta instrukcja trace() ).

var mySample:MyProxy = new MyProxy(); 
mySample.testing(); // method call intercepted: testing

Umieszczenie metod klasy Proxy wewnątrz przestrzeni nazw flash_proxy przynosi dwie korzyści. Po pierwsze, użycie odrębnej przestrzeni nazw upraszcza interfejs publiczny każdej klasy, która rozszerza klasę Proxy. (Klasa Proxy zawiera kilkanaście metod, które można przesłaniać, a które nie są przeznaczone do bezpośredniego wywoływania. Umieszczenie ich wszystkich w przestrzeni nazw public byłoby mylące). Po drugie użycie przestrzeni nazwa flash_proxy pozwala uniknąć konfliktów nazw w sytuacji, gdy podklasa Proxy zawiera metody instancji o nazwach identycznych z nazwami metod klasy Proxy. Załóżmy, że jednej z naszych metod chcemy nadać nazwę callProperty() . Poniższy kod jest formalnie poprawny, ponieważ nasza wersja metody callProperty() znajduje się w innej przestrzeni nazw:

dynamic class MyProxy extends Proxy 
{ 
    public function callProperty() {} 
    flash_proxy override function callProperty(name:*, ...rest):* 
    { 
        trace("method call intercepted: " + name); 
    } 
}

Przestrzenie nazw są także pomocne, gdy chcemy zapewnić dostęp do metod lub właściwości w sposób niemożliwy do zrealizowania za pomocą żadnego z czterech specyfikatorów dostępu ( public , private , internal i protected ). Załóżmy na przykład, że mamy kilka metod pomocniczych rozproszonych po kilku pakietach. Chcemy, aby te metody były dostępne dla wszystkich naszych pakietów, ale nie chcemy deklarować ich jako publicznych. Aby uzyskać pożądany skutek, utworzymy przestrzeń nazw i użyjemy jej jako własnego specjalnego specyfikatora dostępu.

W poniższym przykładzie zastosowano przestrzeń nazw zdefiniowaną przez użytkownika w celu zgrupowania dwóch funkcji rezydujących w różnych pakietach. Zgrupowanie ich w jednej przestrzeni nazw powoduje, że mogą być uwidocznione dla klasy lub pakietu za pomocą jednej instrukcji use namespace .

W tym przykładzie omawianą technikę zademonstrowano przy wykorzystaniu czterech plików. Wszystkie te pliki muszą znajdować się w ścieżce klas. Pierwszy plik, myInternal.as, definiuje przestrzeń nazw myInternal . Ponieważ plik ten znajduje się w pakiecie o nazwie example, należy umieścić go w folderze o nazwie example. Przestrzeń nazw jest oznaczona jako public , a więc można ją importować do innych pakietów.

// myInternal.as in folder example 
package example 
{ 
    public namespace myInternal = "http://www.adobe.com/2006/actionscript/examples"; 
}

Drugi i trzeci plik, Utility.as oraz Helper.as, definiują klasy zawierające metody, które powinny być dostępne w innych pakietach. Klasa Utility znajduje się w pakiecie example.alpha, co oznacza, że plik należy umieścić w folderze o nazwie alpha będącym podfolderem folderu example. Klasa Helper znajduje się w pakiecie example.beta, co oznacza, że plik należy umieścić w folderze o nazwie beta będącym podfolderem folderu example. Oba pakiety, example.alpha i example.beta, muszą zaimportować przestrzeń nazw, zanim zostanie ona użyta.

// 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; 
        } 
    } 
}

Czwarty plik, NamespaceUseCase.as, to główna klasa aplikacji, i należy go umieścić na tym samym poziomie, co folder example. W programie Flash Professional byłaby to klasa dokumentu dla pliku FLA. Klasa NamespaceUseCase również importuje przestrzeń nazw myInternal i używa jej do wywołania dwóch metod statycznych rezydujących w innych pakietach. W przykładzie zastosowano metody statyczne wyłącznie w celu uproszczenia kodu. W przestrzeni nazw myInternal można umieszczać zarówno metody statyczne, jak i metody instancji.

// 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] 
        } 
    } 
}