MooTools 1.2 - programowanie obiektowe - podstawy
22 lipca, 2008
Właściwie termin programowanie obiektowe w tytule tego wpisu trzeba by wziąć w cudzysłowy, ponieważ sam JavaScript jest w pełni obiektowym językiem i używając często najprostszych konstrukcji typu:
alert("jakiś tekst");
W rzeczywistości odnosimy się do metody alert obiektu window. Ale JavaScript nie posiada pewnej cechy znanej z innych obiektowych języków - klas. Dlatego programiści MooTools postanowili podobnie jak w wypadku tablic asocjacyjnych uzupełnić ten brak i stworzyli obiekt Class, który symuluje w tym wypadku tradycyjną klasę znaną chociażby z języków programowania wysokiego poziomu.
Najważniejsze właściwości obiektu Class
Istnieją trzy istotne właściwości obiektu Class: Extends, Implements oraz initialize. Dwie pierwsze z nich są związane z dziedziczeniem natomiast ostatnia z nich jest metodą, która jest odpowiednikiem konstruktora - wykonuje się w momencie stworzenia instancji danej klasy (a właściwie "klasy"). Dziedziczeniem zajmiemy się później, a teraz skupmy się na konstruktorze:
var Komputer = new Class({ initialize: function(typ){ this.type = typ; } }); var nowyKomputer = new Komputer('PC');
Powyższy kod tworzy klasę Komputer, która podczas inicjalizacji ustawia wartość type obiektu na wartość równą argumentowi konstruktora.
Wywołanie:
nowyKomputer.type;
Zwróci nam oczywiście:
"PC"Warto jeszcze zwrócić na jedną ważną sprawę związaną z właściwością initialize obiektu Class - jeżeli jako argument konstruktora podamy funkcję $empty to nie wykona się on podczas tworzenia nowego obiektu danej klasy. Przeanalizujmy dwa fragmenty:
var Komputer = new Class({ initialize: function(typ){ this.type = typ; alert(this.type); } }); var nowyKomputer = new Komputer('PC');
W wypadku powyższego kodu zobaczymy alert o treści "PC". Natomiast w takiej sytuacji:
var Komputer = new Class({ initialize: function(typ){ this.type = typ; alert(this.type); } }); var nowyKomputer = new Komputer($empty);
Nie zobaczymy żadnego alerta, a właściwość type obiektu nowyKomputer dalej będzie miała status undefined, ponieważ $empty jako argument uniemożliwiła wykonanie kodu konstruktora.
Więcej właściwości
Jak już wspominałem obiekt Class posiada trzy ważne właściwości: Implements, Extends oraz initialize. Implements oraz Extends zdefiniowane są w obiekcie Class.Mutators, który zawiera jeszcze właściwości parent oraz parentOf (o nich więcej przy opisie dziedziczenia). Jeżeli jednak uznamy, że potrzebujemy więcej właściwości to wystarczy rozbudować ów obiekt poprzez taki zapis:
Class.Mutators.nowaWlasciwosc = function(){ // kod };
Rozszerzamy możliwości klasy
Jeżeli zajdzie potrzeba rozbudowania klasy w trakcie działania skryptu, a nie chcemy tworzyć klas potomnych to warto pamiętać o metodzie implement obiektu Class, która doda nowe właściwości do istniejącej już klasy:
istniejacaKlasa.implement({ nowaMetoda: function(){ // kod nowej metody } });
Metoda ta jest przydatna w momencie gdy nasza klasa używa jakichś metod tylko w określonej sytuacji, a w pozostałych są one zbędne - wtedy dodajemy owe metody tylko wtedy gdy są rzeczywiście potrzebne, a nie "na zapas".
Pora na dziedziczenie
Co chwila wspominam o dziedziczeniu, więc pora się nim zająć, bo jest to niewątpliwe bardzo ważna kwestia i wielce użyteczna. Do dziedziczenia wykorzystujemy wspomniane właściwości Extends i Implements - pierwsza z nich pozwala określić klasę, której metody będą mogły być użyte w kodzie metod o tej samej nazwie klasy potomnej, natomiast Implements pozwala określić klasę lub tablicę klas (gdy jest ich więcej niż jedna), które udostępniają swoje metody klasie potomnej.
Dziedziczenie przez Extends
W przypadku dziedziczenia z użyciem właściwości Extends możemy rozszerzać istniejące już metody klasy bazowej:
var Komputer = new Class({ initialize: function(typ){ this.type = typ; } }); var Laptop = new Class({ Extends: Komputer, initialize: function(typ, waga){ this.parent(typ); this.weight = waga; } });
W powyższym wypadku tworzymy klasę Komputer, która pozwala określić typ komputera oraz klasę potomną Laptop, która pozwala nie tylko określić typ komputera, ale też jego masę (w wypadku laptopa przyjmijmy to za dość istotną cechę ;)
Zamiast tworzyć zupełnie oddzielną klasę Laptop w postaci:
var Laptop = new Class({ initialize: function(typ, waga){ this.type = typ; this.weight = waga; } });
Dzięki wywołaniu this.parent(argumenty) możemy wywołać metodę o tej samej nazwie co metoda zawierająca ów zapis, ale znajdującą się w klasie bazowej określonej we właściwości Extends. W prezentowanym przypadku może nie widać oszczędności kodu, ale w wypadku bardziej rozbudowanych klas można naprawdę sporo kodu zaoszczędzić dzięki rozsądnej specjalizacji klas potomnych w stosunku do klasy bazowej.
Należy pamiętać, że w wypadku dziedziczenia poprzez Extends nie jest możliwe dziedziczenie wielokrotne - możemy jako klasę bazową podać tylko jedną klasę. Ogólnie ja osobiście widzę w tej kwestii pewne podobieństwo chociażby do języka Ruby w którym także może istnieć tylko jedna klasa bazowa i dowolna ilość miksinów.
Dziedziczenie przez Implements
Dziedziczenie poprzez wykorzystanie właściwości Implements różni się od metody dziedziczenia poprzez Extends tym, że możemy tutaj określić kilka klas bazowych (podajemy je wtedy jako tablicę klas).
Ten sposób dziedziczenia będziemy wykorzystywać w następnych częściach kursu, ale warto się zapoznać z jakimś prostym przykładem. Najważniejsze jest to, że w wypadku tego typu dziedziczenia metody klasy bazowej i potomnej powinny się od siebie różnić nazwami tak by się nie nadpisały:
var Komputer = new Class({ initialize: function(typ){ this.type = typ; } }); var Laptop = new Class({ Implements: Komputer, setWeight: function(waga){ this.weight = waga; } });
W tym wypadku uzyskamy klasę potomną Laptop, która posiada zarówno metodę initialize jak i metodę setWeight. Metoda initialize pochodzi rzecz jasna z klasy bazowej, natomiast druga metoda pochodzi z samej klasy potomnej.
Jeżeli chodzi dziedziczenie z kilku klas naraz to tak jak wspominałem - stosujemy tablicę klas:
var Laptop = new Class({ Implements: [Komputer, Options, Chains, Events], // ... });
Podsumowanie
Poznaliśmy podstawy programowania obiektowego w wydaniu MooTools 1.2 - w kolejnych trzech częściach kursu skupimy się na dodatkowych klasach, które możemy wykorzystać poprzez dziedziczenie: Options, Chains i Events.
Komentarze do wpisu "MooTools 1.2 - programowanie obiektowe - podstawy":
1.
Piter2k1 napisał(a):
16 września 2009, 15:06:30
Istnieje możliwość wywołania klasy przez jej nazwę przechowywaną jako string? chodzi mi o coś takiego:
var nazwa_klasy = "Klasa"; var obiekt = new nazwa_klasy;2.
Dziudek napisał(a):
16 września 2009, 15:11:46
Składniowo to raczej nie przejdzie, ale od takich rzeczy mamy w JavaScript eval ;) Z tym, że należy pamiętać o globalnym aspekcie takiego wywołania - czasem może to stanowić pewien problem ;)
Dodaj komentarz: