Klasy

Klasa jest abstrakcyjną reprezentacją obiektu. W klasie zapisane są informacje o typach danych, jakie obiekt może przechowywać, oraz o możliwych zachowaniach obiektu. Użyteczność takiej abstrakcyjnej reprezentacji nie zawsze jest oczywista, gdy piszemy małe skrypty zawierające zaledwie kilka obiektów wchodzących we wzajemne interakcje. Jednak w miarę rozbudowywania programu wzrasta liczba obiektów, które wymagają zarządzania. W takim przypadku klasy zapewniają lepszą kontrolę nad tworzeniem obiektów oraz nad interakcjami między obiektami.

W języku ActionScript 1.0 programiści mieli do dyspozycji obiekty Function, które pozwalały im na budowanie struktur programistycznych przypominających klasy. W języku ActionScript 2.0 wprowadzono formalną obsługę klas oraz takie słowa kluczowe, jak class oraz extends . Język ActionScript 3.0 nie tylko obsługuje słowa kluczowe wprowadzone w języku ActionScript 2.0, ale również zapewnia nowe możliwości. Na przykład: język ActionScript 3.0 zawiera udoskonalone funkcje kontroli dostępu w postaci atrybutów protected i internal . Zapewnia również lepszą kontrolę nad dziedziczeniem dzięki słowom kluczowym final i override .

Programistom, którzy tworzyli klasy w językach, takich jak Java, C++ lub C#, język ActionScript będzie bardzo przypominał te języki. Język ActionScript wykorzystuje wiele takich samych słów kluczowych i nazw atrybutów, na przykład: class , extends i public .

Uwaga: W dokumentacji Adobe ActionScript termin właściwość oznacza dowolny element obiektu lub klasy, w tym zmienne, stałe i metody. Ponadto, mimo że terminy „zdefiniowany w klasie” i „statyczny” są często używane zamiennie, tutaj oznaczają dwa różne pojęcia. Na przykład: sformułowanie „właściwości klasy” oznacza wszystkie elementy klasy, a nie tylko jej elementy statyczne.

Definicje klas

Składnia definicji klas w języku ActionScript 3.0 jest podobna do obowiązującej w języku ActionScript 2.0 Prawidłowa definicja klasy składa się ze słowa kluczowego class , po którym następuje nazwa klasy. Po nazwie klasy następuje treść klasy, ujęta w nawiasy sześcienne ( {} ). Na przykład poniższy kod tworzy klasę o nazwie Shape zawierającą zmienna o nazwie visible :

public class Shape 
{ 
    var visible:Boolean = true; 
}

Ważna zmianą reguł składni dotyczy definicji klas wewnątrz pakietów. W języku ActionScript 2.0 deklaracja klasy znajdującej się w pakiecie musi zawierać nazwę pakietu. W języku ActionScript 3.0, w którym wprowadzono instrukcję package , nazwa pakietu musi znajdować się w deklaracji pakietu, a nie w deklaracji klasy. Poniżej przedstawiono deklaracje klas ilustrujące sposób zdefiniowania klasy BitmapData (wchodzącej w skład pakietu flash.display) w językach ActionScript 2.0 oraz ActionScript 3.0:

// ActionScript 2.0 
class flash.display.BitmapData {} 
 
// ActionScript 3.0 
package flash.display 
{ 
    public class BitmapData {} 
}

Atrybuty klas

Język ActionScript 3.0 dopuszcza modyfikowanie definicji klas przy użyciu czterech atrybutów:

Atrybut

Definicja

dynamic

Umożliwia dodawanie właściwości do instancji w czasie wykonywania.

final

Zakazuje rozszerzania klasy przez inną klasę.

internal (atrybut domyślny)

Powoduje, że klasa jest widoczna wewnątrz bieżącego pakietu.

public

Powoduje, że klasa jest widoczna wszędzie.

Aby użyć każdego z tych atrybutów, z wyjątkiem internal , należy jawnie przypisać atrybut w definicji. Na przykład brak atrybutu dynamic w definicji klasy spowoduje, że w czasie wykonywania nie będzie można dodać właściwości do instancji tej klasy. Atrybut przypisuje się jawnie, umieszczając go na początku definicji klasy, co ilustruje poniższy kod:

dynamic class Shape {}

Niektórzy czytelnicy być może zwrócili uwagę, że na liście brak atrybutu abstract . W języku ActionScript 3.0 klasy abstrakcyjne nie są obsługiwane. Ponadto lista nie zawiera atrybutów private ani protected . Te atrybuty mają znaczenie wyłącznie wewnątrz definicji klasy i nie mogą być stosowane do samych klas. Jeśli klasa nie powinna być widoczna publicznie poza pakietem, należy umieścić ją w pakiecie i oznaczyć atrybutem internal . Można również pominąć atrybuty internal i public , a wówczas kompilator automatycznie dodaje atrybut internal . Można również zdefiniować klasę, która będzie widoczna tylko w pliku źródłowym, w którym została zdefiniowana. Należy umieścić taką klasę u dołu pliku źródłowego, poniżej zamykającego nawiasu sześciennego definicji pakietu.

Treść klasy

Treść klasy jest ujęta w nawiasy klamrowe. Definiuje zmienne, stałe oraz metodę klasy. Poniższy przykład przedstawia deklarację klasy Accessibility w języku ActionScript 3.0:

public final class Accessibility 
{ 
    public static function get active():Boolean; 
    public static function updateProperties():void; 
}

Wewnątrz treści klasy można także definiować przestrzenie nazw. Poniższy przykład ilustruje definiowanie przestrzeni nazw w treści klasy i wykorzystanie tej przestrzeni jako atrybutu metody klasy:

public class SampleClass 
{ 
    public namespace sampleNamespace; 
    sampleNamespace function doSomething():void; 
}

Język ActionScript 3.0 umożliwia uwzględnienie w treści klasy nie tylko definicji, lecz także instrukcji. Instrukcje w treści klasy, ale znajdujące się poza definicją klasy, są wykonywane dokładnie raz. Do wykonania dochodzi wówczas, gdy definicja klasy zostanie napotkana i gdy zostanie utworzony skojarzony obiekt klasy. Poniższy przykład zawiera wywołanie funkcji zewnętrznej hello() oraz instrukcję trace , która wyświetla komunikat potwierdzający zdefiniowanie klasy:

function hello():String 
{ 
    trace("hola"); 
} 
class SampleClass 
{ 
    hello(); 
    trace("class created"); 
} 
// output when class is created 
hola 
class created

W języku ActionScript 3.0 dozwolone jest zdefiniowanie właściwości statycznej i właściwości instancji o tej samej nazwie w treści tej samej klasy. Poniższy przykładowy kod deklaruje zmienną statyczną o nazwie message oraz zmienną instancji o tej samej nazwie:

class StaticTest 
{ 
    static var message:String = "static variable"; 
    var message:String = "instance variable"; 
} 
// In your script 
var myST:StaticTest = new StaticTest(); 
trace(StaticTest.message); // output: static variable 
trace(myST.message); // output: instance variable

Atrybuty właściwości klas

W omówieniu modelu obiektów języka ActionScript termin właściwość oznacza każdy element, który może należeć do klasy, w tym zmienne, stałe i metody. Jednak w skorowidzu Adobe ActionScript 3.0 dla platformy Adobe Flash ten termin jest stosowany w węższym zakresie. W tym kontekście właściwość obejmuje tylko elementy klasy, które są zmiennymi lub które są zdefiniowane przez metodę pobierania/ustawiania. W języku ActionScript 3.0 istnieje zbiór atrybutów, które mogą być używane z dowolną właściwością klasy. W następującej tabeli wymieniono te atrybuty:

Atrybut

Definicja

internal (atrybut domyślny)

Powoduje, że właściwość jest widoczna wewnątrz tego samego pakietu.

private

Powoduje, że właściwość jest widoczna wewnątrz tej samej klasy.

protected

Powoduje, że właściwość jest widoczna wewnątrz tej samej klasy i jej klas potomnych.

public

Powoduje, że właściwość jest widoczna wszędzie.

static

Określa, że właściwość należy do klasy, a nie do instancji klasy.

UserDefinedNamespace

Niestandardowa przestrzeń nazw zdefiniowana przez użytkownika

Atrybuty przestrzeni nazw sterujące dostępem

Język ActionScript 3.0 udostępnia cztery atrybuty specjalne służące do sterowania dostępem do właściwości zdefiniowanych wewnątrz klasy: public , private , protected i internal .

Atrybut public powoduje, że właściwość będzie widoczna w każdym miejscu skryptu. Na przykład, aby udostępnić metodę dla kodu poza jej pakietem, należy zadeklarować ją z atrybutem public . Zasada ta dotyczy wszystkich właściwości, niezależnie od tego, czy są zadeklarowane za pomocą słowa kluczowego var , const , czy function .

Atrybut private powoduje, że właściwość jest widoczna tylko dla kodu wywołującego w klasie definiującej tę właściwość. Atrybut private działa zatem inaczej niż w języku ActionScript 2.0, gdzie podklasy miały dostęp do klas prywatnych nadklasy. Inna ważna różnica w działaniu dotyczy dostępu w czasie wykonywania. W języku ActionScript 2.0 słowo kluczowe private uniemożliwiało dostęp wyłącznie w trybie kompilacji i dawało się łatwo obejść w czasie wykonywania. W języku ActionScript 3.0 nie jest to już możliwe. Właściwości oznaczone private są niedostępne zarówno w czasie kompilacji, jak i w czasie wykonywania.

Na przykład następujący kod tworzy prostą klasę o nazwie PrivateExample, zawierającą jedną zmienną prywatną, a potem próbuje uzyskać dostęp do tej zmiennej prywatnej spoza klasy.

class PrivateExample 
{ 
    private var privVar:String = "private variable"; 
} 
 
var myExample:PrivateExample = new PrivateExample(); 
trace(myExample.privVar);// compile-time error in strict mode 
trace(myExample["privVar"]); // ActionScript 2.0 allows access, but in ActionScript 3.0, this is a run-time error. 

W języku ActionScript 3.0 próba dostępu do właściwości prywatnej za pomocą kropki ( myExample.privVar ) powoduje błąd kompilacji w trybie ścisłym. W trybie standardowym błąd zostanie zgłoszony podczas wykonywania, podobnie jak przy próbie użycia operatora dostępu do właściwości ( myExample["privVar"] ).

W poniższej tabeli zamieszczono podsumowanie wyników, jakie da próba dostępu do właściwości prywatnej należącej do klasy zapieczętowanej (niedynamicznej):

Tryb ścisły

Tryb standardowy

kropka ( . )

błąd w czasie kompilacji

błąd w czasie wykonywania

nawiasy kwadratowe ( [] )

błąd w czasie wykonywania

błąd w czasie wykonywania

W klasach zadeklarowanych z atrybutem dynamic próba dostępu do zmiennej prywatnej nie powoduje błędu w czasie wykonania. Zmienna nie jest widoczna, dlatego zwracana jest wartość undefined . Jednak próba użycia kropki w trybie ścisłym spowoduje zgłoszenie błędu w czasie kompilacji. Poniższy przykład jest prawie identyczny z poprzednim, z tym że klasa PrivateExample jest zadeklarowana jako dynamiczna:

dynamic class PrivateExample 
{ 
    private var privVar:String = "private variable"; 
} 
 
var myExample:PrivateExample = new PrivateExample(); 
trace(myExample.privVar);// compile-time error in strict mode 
trace(myExample["privVar"]); // output: undefined

Klasy dynamiczne z reguły zwracają wartość undefined , a nie powodują zgłoszenia błędu przy próbie dostępu do właściwości prywatnej z kodu zewnętrznego względem klasy. Zgodnie z poniższą tabelą, błąd jest generowany tylko przy próbie dostępu do właściwości prywatnej za pomocą kropki w trybie ścisłym:

Tryb ścisły

Tryb standardowy

kropka ( . )

błąd w czasie kompilacji

undefined

nawiasy kwadratowe ( [] )

undefined

undefined

Atrybut protected , będący nowym elementem języka ActionScript 3.0, powoduje, że właściwość jest widoczna dla kodu wywołującego wewnątrz jej własnej klasy lub podklas. Innymi słowy, właściwość z atrybutem protected (chroniona) jest dostępna dla własnej klasy i dla wszystkich klas znajdujących się poniżej w hierarchii dziedziczenia. Zasada ta obowiązuje niezależnie od tego, czy podklasy znajdują się w tym samym, czy w różnych pakietach.

Dla użytkowników, którzy wcześniej korzystali z języka ActionScript 2.0, ta funkcja jest podobna do atrybutu private w języku ActionScript 2.0. Atrybut protected w języku ActionScript 3.0 jest również podobny do atrybutu protected w języku Java. Obydwa atrybuty różnią się jednak, ponieważ wersja Java zapewnia dostęp do modułów wywołujących w tym samym pakiecie. Atrybut protected jest użyteczny, jeśli mamy zmienną lub metodę potrzebną w podklasach, ale chcemy ukryć ją przed kodem zewnętrznym względem łańcucha dziedziczenia

Atrybut internal , będący nowym elementem języka ActionScript 3.0, powoduje, że właściwość jest widoczna dla kodu wewnątrz jej własnego pakietu. Jest to domyślny atrybut dla kodu w pakiecie i obowiązuje dla każdej właściwości, której jawnie nie przypisano żadnego z poniższych atrybutów:

  • public

  • private

  • protected

  • przestrzeni nazw zdefiniowanej przez użytkownika

Atrybut internal działa podobnie jak domyślna kontrola dostępu w języku Java, z tym że w języku Java ten poziom dostępu nie ma jawnej nazwy i deklarowany jest po prostu przez pominięcie innych modyfikatorów dostępu. Atrybut internal w języku ActionScript 3.0 umożliwia jawne wyrażenie zamiaru uwidocznienia właściwości wyłącznie dla kodu w jej pakiecie.

Atrybut static

Atrybut static , którego można używać z właściwościami zadeklarowanymi za pomocą słów kluczowych var , const lub function , umożliwia powiązanie właściwości z klasą, a nie z instancjami tej klasy. Kod zewnętrzny względem klasy odwołuje się do właściwości statycznych za pośrednictwem nazwy klasy, a nie nazwy instancji.

Właściwości statyczne nie są dziedziczone przez podklasy, ale właściwości stanowią część łańcucha zasięgów podklas. Oznacza to, że w treści podklasy można używać zmiennej lub metody statycznej bez odwoływania się do klasy, w której została ona zdefiniowana.

Atrybuty w postaci przestrzeni nazw zdefiniowanych przez użytkownika

Alternatywą dla wstępnie zdefiniowanych atrybutów kontroli dostępu jest utworzenie niestandardowych przestrzeni nazw i korzystanie z nich jak z atrybutów. W każdej definicji można użyć tylko jednego atrybutu w postaci przestrzeni nazw, a ponadto nie można używać przestrzeni nazw razem z którymkolwiek z atrybutów kontroli dostępu: ( public , private , protected , internal ).

Zmienne

Zmienne można deklarować za pomocą słów kluczowych var lub const . Wartości zmiennych zadeklarowanych za pomocą słowa kluczowego var można zmieniać wielokrotnie podczas wykonywania skryptu. Zmienne zadeklarowane za pomocą słowa kluczowego const są nazywane stałymi i można im przypisać wartość tylko raz. Próba przypisania nowej wartości do zainicjowanej stałej spowoduje błąd.

Zmienne statyczne

Zmienne statyczne deklaruje się za pomocą kombinacji słowa kluczowego static oraz instrukcji var albo const . Zmienne statyczne, powiązane z klasą, a nie z instancją klasy, są użyteczne do przechowywania i współużytkowania informacji należących do całej klasy obiektów. Zmienna statyczna będzie np. dobrym rozwiązaniem, jeśli chcemy rejestrować, ile instancji danej klasy utworzono, lub jeśli chcemy zapisać maksymalną dozwoloną liczbę instancji.

W poniższym przykładzie tworzona jest zmienna totalCount , która zlicza utworzone instancje klasy, oraz stała MAX_NUM zawierająca maksymalną liczbę instancji. Zmienne totalCount i MAX_NUM są statyczne, ponieważ zawierają wartości, które mają zastosowanie do klasy jako całości, a nie do konkretnej instancji.

class StaticVars 
{ 
    public static var totalCount:int = 0; 
    public static const MAX_NUM:uint = 16; 
}

Kod zewnętrzny względem klasy StaticVars i wszystkich jej podklas może odwoływać się do właściwości totalCount i MAX_NUM tylko za pośrednictwem samej klasy. Oto przykład poprawnego kodu:

trace(StaticVars.totalCount); // output: 0 
trace(StaticVars.MAX_NUM); // output: 16

Nie są dozwolone odwołania do zmiennych statycznych za pośrednictwem instancji klasy, dlatego następujący kod spowoduje zgłoszenie błędów:

var myStaticVars:StaticVars = new StaticVars(); 
trace(myStaticVars.totalCount); // error 
trace(myStaticVars.MAX_NUM); // error

Zmienne zadeklarowane za pomocą słów kluczowych static i const muszą być inicjowane w deklaracji stałej, co widzimy w deklaracji MAX_NUM w przykładowej klasie StaticVars. Nie można przypisać wartości do stałej MAX_NUM wewnątrz konstruktora lub metody instancji. Poniższy kod powoduje zgłoszenie błędu, ponieważ zastosowano w nim niepoprawny sposób inicjowania stałej statycznej:

// !! Error to initialize static constant this way 
class StaticVars2 
{ 
    public static const UNIQUESORT:uint; 
    function initializeStatic():void 
    { 
        UNIQUESORT = 16; 
    } 
}

Zmienne instancji

Do zmiennych instancji zalicza się właściwości zadeklarowane za pomocą słów kluczowych var i const , ale bez słowa kluczowego static . Zmienne instancji, powiązane z instancjami klasy, a nie z całą klasą, są użyteczne do przechowywania wartości specyficznych dla instancji. Na przykład klasa Array ma właściwość instancji o nazwie length , która przechowuje liczbę elementów tablicy konkretnej instancji klasy Array.

Niedozwolone jest przesłanianie zmiennych instancji w podklasie, niezależnie od tego, czy zostały zadeklarowane jako var , czy jako const . Efekt zbliżony do przesłonięcia zmiennej można jednak uzyskać, przesłaniając metody pobierające i ustawiające.

Metody

Metody są funkcjami stanowiącymi część definicji klasy. Z chwilą utworzenia instancji klasy metoda zostaje powiązana z tą instancją. W przeciwieństwie do funkcji zadeklarowanych poza klasą, metody nie można używać w oderwaniu od instancji, z którą jest powiązania.

Do definiowania metod służy słowo kluczowe function . Podobnie, jak w przypadku każdej właściwości klasy, do metod można zastosować dowolne atrybuty właściwości klas, między innymi private, protected, public, internal, static lub custom namespace. Można również użyć instrukcji funkcji, takiej jak poniższa:

public function sampleFunction():String {}

Można też użyć zmiennej, której przypisane zostanie wyrażenie funkcyjne, w następujący sposób:

public var sampleFunction:Function = function () {}

W większości przypadków należy użyć instrukcji funkcyjnej, a nie wyrażenia, co wynika z następujących powodów:

  • Instrukcje funkcyjne są bardziej zwięzłe i czytelne.

  • Instrukcje funkcyjne umożliwiają stosowanie słów kluczowych override i final .

  • Instrukcje funkcyjne tworzą silniejsze powiązanie między identyfikatorem — tj. nazwą funkcji — a kodem w treści metody. Ponieważ wartość zmiennej można zmienić za pomocą instrukcji przypisania, połączenie między zmienną a jej wyrażeniem funkcyjnym może zostać w dowolnej chwili zerwane. Mimo że istnieje obejście tego problemu, polegające na zadeklarowaniu zmiennej za pomocą słowa const , a nie var , takie postępowanie nie należy do dobrej praktyki programistycznych, ponieważ utrudnia zrozumienie kodu i uniemożliwia stosowanie słów kluczowych override i final .

Do sytuacji, w których konieczne jest użycie wyrażenia funkcyjnego, należy powiązanie funkcji z obiektem prototypowym.

Konstruktory

Konstruktory (nazywane też metodami-konstruktorami) to funkcje o tej samej nazwie, co klasa, w której są zdefiniowane. Kod zawarty w konstruktorze jest wykonywany za każdym razem, gdy za pomocą słowa kluczowego new tworzona jest nowa instancja klasy. Na przykład w poniższym kodzie zdefiniowano prostą klasę o nazwie Example, która zawiera jedną właściwość o nazwie status . Wartość początkowa zmiennej status jest przypisywana wewnątrz konstruktora.

class Example 
{ 
    public var status:String; 
    public function Example() 
    { 
        status = "initialized"; 
    } 
} 
 
var myExample:Example = new Example(); 
trace(myExample.status); // output: initialized

Konstruktory mogą być tylko publiczne, ale użycie atrybutu public jest opcjonalne. W odniesieniu do konstruktora nie można używać żadnych innych specyfikatorów dostępu, w tym private , protected lub internal . Konstruktora nie można również zadeklarować w przestrzeni nazw zdefiniowanej przez użytkownika.

Konstruktor może jawnie wywołać konstruktor swojej bezpośredniej nadklasy. Służy do tego instrukcja super() . Jeśli konstruktor nadklasy nie zostanie wywołany jawnie, kompilator automatycznie wstawi wywołanie przed pierwszą instrukcją w treści konstruktora. Możliwa jest również wywoływanie metod nadklasy poprzez dodanie przedrostka super jako odwołania do nadklasy. Jeśli w tym samym konstruktorze ma być używana zarówno instrukcja super() , jak i przedrostek super , to instrukcja super() musi występować wcześniej. W przeciwnym razie odwołanie przez przedrostek super nie będzie działać zgodnie z oczekiwaniami. Konstruktor super() należy także wywołać przed ewentualną instrukcją throw lub return .

Poniższy przykład ilustruje skutki użycia odwołania super przed wywołaniem konstruktora super() . Nowa klasa, ExampleEx, rozszerza klasę Example. Konstruktor ExampleEx próbuje uzyskać dostęp do zmiennej status zdefiniowanej w jego nadklasie, ale próba ta ma miejsce przed wywołaniem super() . Instrukcja trace() w konstruktorze ExampleEx wyświetla wartość null , ponieważ zmienna status nie jest dostępna przed wykonaniem konstruktora super() .

class ExampleEx extends Example 
{ 
    public function ExampleEx() 
    { 
        trace(super.status); 
        super(); 
    } 
} 
 
var mySample:ExampleEx = new ExampleEx(); // output: null

Mimo że formalnie dozwolone jest użycie instrukcji return w konstruktorze, nie jest dozwolone zwrócenie wartości. Innymi słowy, instrukcja return nie może być skojarzona z wyrażeniem lub wartością. W związku z tym konstruktory nie mogą zwracać wartości i nie mogą mieć określonego typu zwracanej wartości.

Jeśli w klasie nie zostanie zdefiniowany konstruktor, kompilator automatycznie utworzy pustą metodę-konstruktor. Jeśli klasa rozszerza inną klasę, kompilator doda wywołanie super() do wygenerowanego konstruktora.

metody statyczne

Metody statyczne, nazywane także metodami klas , to metody zadeklarowane ze słowem kluczowym static . Metody statyczne, które są powiązane z klasą, a nie z instancją klasy, są przydatne do enkapsulacji funkcjonalności wpływającej na coś innego niż stan konkretnej instancji. Ponieważ metody statyczne są powiązane z klasą jako całością, dostęp do nich jest możliwy tylko za pośrednictwem klasy, a nie jej instancji.

Metody statyczne są przydatne do enkapsulacji funkcjonalności, która nie ogranicza się do zmiany stanu instancji klasy. Innymi słowy, metoda powinna być statyczna, jeśli jej działanie nie wpływa bezpośrednio na wartość instancji klasy. Na przykład klasa Date ma metodę statyczną o nazwie parse() , która konwertuje ciąg znaków na liczbę. Metoda jest statyczna, ponieważ nie wpływa na poszczególne instancje klasy. Metoda parse() analizuje ciąg znaków reprezentujący wartość daty i zwraca liczbę zgodną z wewnętrzną reprezentacją obiektu Date. Ta metoda nie jest metodą instancji, ponieważ nie ma sensu stosowanie jej do instancji klasy Date.

Porównajmy teraz metodę statyczną parse() z jedną z metod instancji klasy Date, np. z metodą getMonth() . getMonth() to metoda instancji, ponieważ operuje bezpośrednio na wartości instancji, pobierając konkretny składnik — miesiąc — instancji Date.

Ponieważ metody statyczne nie są powiązane z poszczególnymi instancjami, nie jest dozwolone użycie słów kluczowych this lub super w treści metody statycznej. Zarówno odwołanie this , jak i odwołanie super , mają znaczenie tylko w kontekście metody instancji.

Inaczej niż w niektórych innych językach programowania opartych na koncepcji klas, metody statyczne w języku ActionScript 3.0 nie są dziedziczone.

Metody instancji

Metody instancji są to metody zadeklarowane bez słowa kluczowego static . Metody instancji, które są powiązane z instancjami klasy, a nie z klasą jako całością, są użyteczne przy implementowaniu funkcjonalności wpływającej na poszczególne instancje klasy. Na przykład klasa Array zawiera metodę instancji o nazwie sort() , która operuje bezpośrednio na instancjach klasy Array.

Zarówno zmienne statyczne, jak i zmienne instancji znajdują się w zasięgu treści metody instancji, co oznacza, że do zmiennych zdefiniowanych w tej samej klasie można odwoływać się za pomocą prostych identyfikatorów. Na przykład poniższa klasa, CustomArray, rozszerza klasę Array. Klasa CustomArray definiuje zmienną statyczną o nazwie arrayCountTotal , która rejestruje łączną liczbę instancji klasy, zmienną instancji o nazwie arrayNumber , która rejestruje kolejność tworzenia instancji, oraz metodę instancji o nazwie getPosition() , która zwraca wartości tych zmiennych.

public class CustomArray extends Array 
{ 
    public static var arrayCountTotal:int = 0; 
    public var arrayNumber:int; 
 
    public function CustomArray() 
    { 
        arrayNumber = ++arrayCountTotal; 
    } 
     
    public function getArrayPosition():String 
    { 
         return ("Array " + arrayNumber + " of " + arrayCountTotal); 
    } 
}

Mimo że kod zewnętrzny względem klasy musi mieć dostęp do zmiennej statycznej arrayCountTotal za pośrednictwem obiektu klasy, w formie CustomArray.arrayCountTotal , kod rezydujący w treści metody getPosition() może odwoływać się bezpośrednio do zmiennej statycznej arrayCountTotal . Zasada ta obowiązuje nawet dla zmiennych statycznych w nadklasach. Chociaż w języku ActionScript 3.0 właściwości statyczne nie są dziedziczone, właściwości statyczne z nadklas należą do aktualnego zasięgu. Na przykład klasa Array zawiera kilka zmiennych statycznych, z których jedna jest stałą o nazwie DESCENDING . Kod rezydujący w podklasie Array może mieć dostęp do statycznej stałej DESCENDING za pomocą prostego identyfikatora:

public class CustomArray extends Array 
{ 
    public function testStatic():void 
    { 
        trace(DESCENDING); // output: 2 
    } 
}

Wartość odwołania this w treści metody instancji jest odwołaniem do instancji, z którą ta metoda jest powiązana. Poniższy kod demonstruje, że odwołanie this wskazuje na instancję zawierającą metodę:

class ThisTest 
{ 
    function thisValue():ThisTest 
    { 
        return this; 
    } 
} 
 
var myTest:ThisTest = new ThisTest(); 
trace(myTest.thisValue() == myTest); // output: true

Dziedziczeniem metody instancji można sterować za pomocą słów kluczowych override i final . Atrybut override umożliwia przedefiniowanie metody odziedziczonej, a atrybut final zapobiega przesłanianiu metody przez podklasy.

Akcesory pobierające i ustawiające

Funkcje-akcesory pobierające i ustawiające, nazywane także metodami pobierającymi i metodami ustawiającymi , umożliwiają realizację koncepcji ukrywania i enkapsulacji informacji, a jednocześnie stworzenie wygodnego interfejsu programistycznego dla samodzielnie tworzonych klas. Funkcje pobierające i ustawiające pozwalają na zachowanie prywatności właściwości klasy, ale jednocześnie umożliwiają użytkownikom klasy dostęp do tych właściwości w taki sposób, jak do zmiennych, a nie w formie wywołania metody klasy.

Zaletą takiej strategii jest możliwość uniknięcia tradycyjnych akcesorów o „nieprzyjaznych” nazwach, takich jak getPropertyName() i setPropertyName() . Inną zaletą funkcje pobierających i ustawiających jest możliwość obycia się bez pary funkcji publicznych przypadającej na każdą właściwość, która ma być dostępna i do odczytu, i do zapisu.

Poniższa klasa przykładowa o nazwie GetSet zawiera funkcje pobierającą i ustawiającą o nazwie publicAccess() , która umożliwia dostęp do zmiennej prywatnej o nazwie privateProperty :

class GetSet 
{ 
    private var privateProperty:String; 
     
    public function get publicAccess():String 
    { 
        return privateProperty; 
    } 
     
    public function set publicAccess(setValue:String):void 
    { 
        privateProperty = setValue; 
    } 
}

Próba bezpośredniego dostępu do właściwości privateProperty powoduje zgłoszenie błędu:

var myGetSet:GetSet = new GetSet(); 
trace(myGetSet.privateProperty); // error occurs

Użytkownik klasy GetSet ma natomiast do dyspozycji mechanizm, który z pozoru przypomina właściwość o nazwie publicAccess , ale faktycznie jest parą akcesorów — złożoną z funkcji pobierającej i ustawiającej — operujących na właściwości prywatnej privateProperty . W poniższym przykładzie tworzona jest instancja klasy GetSet, a następnie wartość właściwości privateProperty ustawiana jest za pomocą publicznego akcesora o nazwie publicAccess :

var myGetSet:GetSet = new GetSet(); 
trace(myGetSet.publicAccess); // output: null 
myGetSet.publicAccess = "hello"; 
trace(myGetSet.publicAccess); // output: hello

Funkcje pobierające i ustawiające umożliwiają także przesłanianie właściwości dziedziczonych z nadklasy, co nie jest możliwe w przypadku zwykłych zmiennych należących do klasy. Zmienne należące do klasy zadeklarowane za pomocą słowa kluczowego var nie mogą być przesłaniane w podklasach. Jednak ograniczenie to nie obowiązuje w przypadku właściwości tworzonych za pomocą funkcji pobierających i ustawiających. W odniesieniu do funkcji pobierających i ustawiających odziedziczonych z nadklasy można używać atrybutu override .

Metody powiązane

Metoda powiązana, nazywana czasem zamknięciem metody , to po prostu metoda wyodrębniona z jej instancji. Przykładami metod powiązanych są metody przekazywane jako argumenty do funkcji lub zwracane jako wartości z funkcji. Metody powiązane, będące nowym elementem języka ActionScript 3.0, są podobne do zamknięć funkcji w tym, że zachowują swoje środowisko leksykalne nawet po wyodrębnieniu z instancji. Zasadnicza różnica między metodą powiązaną a zamknięciem funkcji polega na tym, że odwołanie this w metodzie powiązanej pozostaje powiązane z instancją implementującą tą metodę. Innymi słowy, odwołanie this w metodzie powiązanej zawsze wskazuje na oryginalny obiekt, który zaimplementował metodę. W przypadku zamknięć funkcji odwołanie this ma charakter ogólny, czyli wskazuje na obiekt lub funkcję, z którym jest skojarzone w momencie wywołania.

Zrozumienie koncepcji metod powiązanych jest ważne w przypadku posługiwania się słowem kluczowym this . Jak pamiętamy, słowo kluczowe this jest odwołaniem do obiektu nadrzędnego metody. Większość programistów używających języka ActionScript oczekuje, że słowo kluczowe this przedstawia obiekt lub klasę zawierającą definicję metody. Jednak bez mechanizm wiązania metod warunek ten nie zawsze byłby spełniony. Na przykład we wcześniejszych wersjach języka ActionScript odwołanie this nie zawsze wskazywało na instancję, która implementowała metodę. W języku ActionScript 2.0 w metodach wyodrębnionych z instancji nie tylko słowo kluczowe this nie było powiązane z oryginalną instancją, lecz również nie były dostępne zmienne i metody należące do klasy instancji. Nie stanowi to problemu w języku ActionScript 3.0, w którym metody powiązane są tworzone automatycznie podczas przekazywania metod jako parametrów. Metody powiązane gwarantują, że słowo kluczowe this zawsze odwołuje się do obiektu lub klasy, w którym metoda jest zdefiniowana.

Poniższy kod definiuje klasę o nazwie ThisTest, która zawiera metodę o nazwie foo() definiującą metodę powiązaną, a także metodę o nazwie bar() , która zwraca metodę powiązaną. Kod zewnętrzny względem klasy tworzy instancję klasy ThisTest, wywołuje metodę bar() i zapisuje zwróconą wartość w zmiennej o nazwie myFunc .

class ThisTest 
{ 
    private var num:Number = 3; 
    function foo():void // bound method defined 
    { 
        trace("foo's this: " + this); 
        trace("num: " + num); 
    } 
    function bar():Function 
    { 
        return foo; // bound method returned 
    } 
} 
 
var myTest:ThisTest = new ThisTest(); 
var myFunc:Function = myTest.bar(); 
trace(this); // output: [object global] 
myFunc(); 
/* output:  
foo's this: [object ThisTest] 
output: num: 3 */

Ostatnie dwa wiersze kodu demonstrują fakt, że odwołanie this w metodzie powiązanej foo() nadal wskazuje na klasę ThisTest, mimo że odwołanie this w wierszy bezpośrednio poprzedzającym wskazuje na obiekt globalny. Co więcej, metoda powiązana przechowywana w zmiennej myFunc wciąż ma dostęp do zmiennych klasy ThisTest. Gdyby ten sam kod został uruchomiony w języku ActionScript 2.0, odwołania this byłyby identyczne, a zmienna num miałaby wartość undefined .

Jednym z obszarów, w których nowa koncepcja metod powiązanych jest najbardziej zauważalna, są podprogramy obsługi zdarzeń, ponieważ metoda addEventListener() wymaga, aby jako argument przekazać do niej funkcję lub metodę.

Wyliczenia w oparciu o klasy

Wyliczenia to niestandardowe typy danych, które definiuje się w celu enkapsulacji małego zbioru wartości. W języku ActionScript 3.0 nie istnieje specjalny mechanizm wyliczeń, porównywalny ze słowem kluczowym enum w języku C++ lub interfejsem Enumeration w języku Java. Możliwe jest jednak tworzenie wyliczeń przy użyciu klas i stałych statycznych. Na przykład: klasa PrintJob w języku ActionScript 3.0 korzysta z wyliczenia o nazwie PrintJobOrientation zawierającego wartości: "landscape" i "portrait" , co ilustruje poniższy kod:

public final class PrintJobOrientation 
{ 
    public static const LANDSCAPE:String = "landscape"; 
    public static const PORTRAIT:String = "portrait"; 
}

Przyjęto konwencję, że klasa wyliczeniowa powinna być zadeklarowana z atrybutem final , ponieważ nie ma potrzeby rozszerzania klasy. Klasa zawiera tylko elementy statyczne, co oznacza, że użytkownik nie tworzy instancji klasy. Dostęp do wartości wyliczenia odbywa się wprost przez obiekt klasy, co ilustruje poniższy fragment kodu:

var pj:PrintJob = new PrintJob(); 
if(pj.start()) 
{ 
    if (pj.orientation == PrintJobOrientation.PORTRAIT) 
    { 
        ... 
    } 
    ... 
}

Wszystkie klasy wyliczeniowe języka ActionScript 3.0 zawierają tylko zmienne typu String, int lub uint. Korzyścią ze stosowania wyliczeń w miejsce literalnych ciągów lub wartości liczbowych jest możliwość łatwiejszego znajdowania błędów typograficznych. W wypadku pomyłki w zapisie wartości wyliczeniowej kompilator języka ActionScript zgłosi błąd. Gdy natomiast używane są literały, kompilator nie sygnalizuje obecności nieprawidłowo wpisanego słowa lub błędnej liczby. W poprzednim przykładzie kompilator generuje błąd, jeśli nazwa stałej wyliczeniowej jest nieprawidłowa, co ilustruje następujący fragment:

    if (pj.orientation == PrintJobOrientation.PORTRAI) // compiler error

Jednak kompilator nie zgłosi błędu w razie pomyłki w zapisie literalnego ciągu znaków:

    if (pj.orientation == "portrai") // no compiler error

Druga technika tworzenia wyliczeń również wymaga utworzenia osobnej klasy ze statycznymi właściwościami dla wartości wyliczeniowych. Jednak różni się od pierwszej tym, że każda z właściwości statycznych zawiera instancję klasy, a nie ciąg znaków lub wartość całkowitą. Poniższy przykładowy kod tworzy klasę wyliczeniową zawierającą dni tygodnia:

public final class Day 
{ 
    public static const MONDAY:Day = new Day(); 
    public static const TUESDAY:Day = new Day(); 
    public static const WEDNESDAY:Day = new Day(); 
    public static const THURSDAY:Day = new Day(); 
    public static const FRIDAY:Day = new Day(); 
    public static const SATURDAY:Day = new Day(); 
    public static const SUNDAY:Day = new Day(); 
}

Ta technika nie jest stosowana w języku ActionScript 3.0, ale wielu programistów korzysta z niej z uwagi na ściślejszą kontrolę typów. Na przykład metoda, która zwraca wartość wyliczeniową, może ograniczyć zbiór wartości zwracanych do konkretnego typu wyliczeniowego. Poniższy kod ilustruje nie tylko funkcję zwracającą dzień tygodnia, lecz również wywołanie funkcji, w której typ wyliczeniowy został użyty jako wskazany typ zadeklarowany:

function getDay():Day 
{ 
    var date:Date = new Date(); 
    var retDay:Day; 
    switch (date.day) 
    { 
        case 0: 
            retDay = Day.MONDAY; 
            break; 
        case 1: 
            retDay = Day.TUESDAY; 
            break; 
        case 2: 
            retDay = Day.WEDNESDAY; 
            break; 
        case 3: 
            retDay = Day.THURSDAY; 
            break; 
        case 4: 
            retDay = Day.FRIDAY; 
            break; 
        case 5: 
            retDay = Day.SATURDAY; 
            break; 
        case 6: 
            retDay = Day.SUNDAY; 
            break; 
    } 
    return retDay; 
} 
 
var dayOfWeek:Day = getDay();

Możemy udoskonalić klasę Day w taki sposób, aby kojarzyła liczbę całkowitą z każdym dniem tygodnia i udostępniała metodę toString() zwracającą ciąg znaków z nazwą dnia.

Klasy zasobów osadzonych

W języku ActionScript 3.0 istnieją specjalne klasy, nazywane klasami zasobów osadzonych , służące do reprezentacji zasobów osadzonych. Zasób osadzony to zasób, taki jak dźwięk, obraz lub czcionka, włączony do pliku SWF w czasie kompilacji. Osadzenie zasobu, jako alternatywa dla dynamicznego ładowania go, gwarantuje dostępność zasobu w czasie wykonywania, jednak kosztem większej objętości pliku SWF.

Korzystanie z klas zasobów osadzonych w środowisku Flash Professional

Aby osadzić zasób, należy najpierw umieścić go w bibliotece pliku FLA. Następnie, korzystając z właściwości połączenia zasobu, należy podać nazwę klasy zasobu osadzonego. Jeśli klasy o tej nazwie nie ma w ścieżce klas, to zostanie automatycznie wygenerowana. Następnie tworzymy instancję klasy zasobu osadzonego i korzystamy z właściwości i metod zdefiniowanych lub odziedziczonych przez tę klasę. Poniższy przykładowy kod umożliwia odtworzenie osadzonego dźwięku połączonego z klasą zasobu osadzonego o nazwie PianoMusic:

var piano:PianoMusic = new PianoMusic(); 
var sndChannel:SoundChannel = piano.play();

Można również wykorzystać znacznik metadanych [Embed] w celu osadzenia zasobów w projekcie Flash Professional, co zostało opisane w dalszej części niniejszego podręcznika. Jeśli w kodzie używany jest znacznik [Embed] , program Flash Professional wykorzystuje kompilator Flex w celu skompilowania projektu, nie korzysta natomiast z kompilatora Flash Professional.

Korzystanie z osadzonych klas zasobów, które wykorzystują kompilator Flex

W przypadku kompilowania kodu za pomocą kompilatora Flex w celu osadzenia zasobu w kodzie ActionScript należy użyć znacznika metadanych [Embed] . Zasób należy umieścić w głównym folderze źródłowym lub innym folderze w ścieżce budowania projektu. Gdy tylko kompilator Flex napotyka znacznik Embed, tworzy klasę zasobu osadzonego. Dostęp do tej klasy jest możliwy za pośrednictwem zmiennej o typie danych Class, którą deklaruje się bezpośrednio po znaczniku metadanych [Embed] . W poniższym przykładowym kodzie osadzony jest dźwięk o nazwie sound1.mp3, a odwołanie do klasy zasobu osadzonego powiązanej z tym dźwiękiem jest przechowywane w zmiennej o nazwie soundCls . Następnie przykładowy kod tworzy instancję klasy obiektu osadzonego i wywołuje metodę play() tej instancji:

package 
{ 
    import flash.display.Sprite; 
    import flash.media.SoundChannel; 
    import mx.core.SoundAsset; 
 
    public class SoundAssetExample extends Sprite 
    { 
        [Embed(source="sound1.mp3")] 
        public var soundCls:Class; 
         
        public function SoundAssetExample() 
        { 
            var mySound:SoundAsset = new soundCls() as SoundAsset; 
            var sndChannel:SoundChannel = mySound.play(); 
        } 
    } 
}

Adobe Flash Builder

Aby użyć znacznika metadanych [Embed] w projekcie ActionScript w środowisku Flash Builder, należy zaimportować wszelkie potrzebne klasy ze środowiska Flex. Na przykład, aby osadzać dźwięki, należy zaimportować klasę mx.core.SoundAsset. Aby użyć środowiska Flex, należy umieścić plik framework.swc w ścieżce budowania projektu ActionScript. Spowoduje to zwiększenie wielkości pliku SWF.

Adobe Flex

We Flex alternatywny sposób osadzania zasobów polega na użyciu dyrektywy @Embed() w definicji znacznika MXML.