MooTools 1.2 - programowanie obiektowe - podstawy
08 marca, 2008
Tym wpisem rozpoczynamy kolejny (dwuczęściowy) fragment kursu. Będzie on poświęcony temu jak MooTools 1.2 wspomaga programowanie obiektowe w JavaScript (wspomaga, bo trzeba pamiętać iż JavaScript to język z natury w pełni obiektowy). Dzięki MooTools możemy w czytelny sposób zarządzać klasami swojego projektu. Po tych dwóch częściach kursu będzie jasne dlaczego wywołania pewnych klas zapisujemy w taki, a nie inny sposób. Właściwe jest to klucz do zrozumienia składni MooTools. W tej części zajmiemy się podstawami podstaw - stworzymy kilka klas, część z nich rozszerzymy, innym stworzymy klasy potomne itp.
Teoretycznie powinienem zacząć od dogłębnego opisu istoty programowania obiektowego, ale wtedy potrzebowałbym kilku wpisów na samą teorię. Pozwolę sobie na bardzo zwięzły i momentami może nawet bardzo prosty jak na złożoność tematu opis zagadnienia programowania obiektowego.
Na co pozwala nam programowanie obiektowe ? Na bardziej naturalne niż w wypadku programowania strukturalnego rozwiązanie problemu. Można powiedzieć, że tworzymy swoiste twory, które później wykorzystujemy do osiągnięcia zamierzonego celu. Te twory to klasy, które są wzorcami dla obiektów. Czyli obiekt to coś co zostało stworzone na bazie informacji zawartych w klasie. A klasa posiada właściwości i metody. Metody to funkcje, a właściwości to wartości wykorzystywane w trakcie działania obiektu. To co zdefiniujemy w klasie, będzie można później wykorzystać w obiektach. Dodatkowo możemy na bazie jednej klasy tworzyć klasy potomne - pewne obiekty mają cechy wspólne - zamiast tworzyć je od podstaw, możemy zebrać elementy wspólne w jednej klasie, a resztę metod i właściwości umieścić w unikalnych klasach.
Pora na jakiś mały przykład - przyjmijmy, że mamy napisać pewną aplikację, która ma za zadanie zasymulować w pewnym stopniu "życie" jakiejś instytucji, dajmy na to uczelni (bliskie mi klimaty ;)). Normalnie napisalibyśmy kilkaset czy nawet kilka tysięcy funkcji, które ciężko byłoby ogarnąć. Gdybyśmy wykorzystali klasy sytuacja staje się prostsza - możemy sobie na początek stworzyć klasę Człowiek, na jej bazie utworzyć klasy potomne np. Wykładowca, Student, Szatniarka itd. (to przecież ludzie więc wiele cech mają wspólnych). Do tego stworzyć klasę Pomieszczenie opisującą pomieszczenia i sytuacje jakie mogą mieć w nich miejsce... I tak dalej, i tak dalej... W wypadku wersji obiektowej naszego hipotetycznego symulatora będzie od razu widać powiązania pomiędzy poszczególnymi elementami aplikacji. Można w dużym uproszczeniu powiedzieć, że te tysiące funkcji zostaną zgrupowane i posegregowane w klasach. Oczywiście programowanie obiektowe daje nam wiele innych dodatkowych możliwości, ale nie ma tutaj miejsca na opisanie tego wszystkiego - zainteresowanym (czyli tym, którzy nie zgłębili jeszcze idei programowania obiektowego) polecam zgłębienie tego tematu, gdyż pozwala on na uzyskanie zupełnie nowej jakości w tworzonych aplikacjach.
Nas poza uporządkowaniem struktury aplikacji, będzie jeszcze interesować druga ważna rzecz - skalowalność i elastyczność jaką możemy osiągnąć dzięki programowaniu obiektowemu.
Pora na stworzenie naszej pierwszej klasy z użyciem MooTools - nie jest to skomplikowane i bazuje na poniższym wzorcu:
var NazwaKlasy = new Class({właściwości_i_metody});
Na przykład:
var Aplikacja = new Class({
uruchom: function(){
alert("Aplikacja uruchomiona...");
},
zamknij: function(){
alert("Aplikacja została zakończona...");
}
});
W ten oto sposób stworzyliśmy naszą pierwszą klasę z dwoma metodami. Przydałoby się jeszcze dodać parę właściwości. Ale najpierw słów kilka o operatorze this - pozwala on nam na odwoływanie się bezpośrednio do klasy. Tu wspomnę, że aby uruchomić jakąś metodę klasy trzeba stworzyć obiekt tejże klasy, a następnie dokonać wywołania funkcji z obiektu:
obiekt.nazwaMetody();
z właściwościami jest podobnie:
obiekt.wlasciwosc;
Sam obiekt klasy tworzymy poprzez zapis:
var Obiekt = new NazwaKlasy();
Aby odwołać się do jakiejś właściwości klasy w wewnątrz jej definicji, musimy wykorzystać operator this, tj.:
this.wlasciwosc;
Gdy chcemy w metodzie danej klasy odwołać się do jej właściwości.
Rozbudujmy naszą klasę o właściwość uruchomiona, i zmodyfikujmy metody tak by zmieniały one zawartość tej właściwości - dzięki temu zamiast alertów będziemy mogli odczytywać status nasze "aplikacji" poprzez właściwości:
var Aplikacja = new Class({
uruchomiona: false,
uruchom: function(){
this.uruchomiona = true;
},
zamknij: function(){
this.uruchomiona = false;
}
});
A teraz stworzymy obiekt tej klasy i pozmieniajmy jego właściwość:
var TestowaAplikacja = new Aplikacja();
TestowaAplikacja.uruchom();
alert(TestowaAplikacja.uruchomiona);
TestowaAplikacja.zamknij();
alert(TestowaAplikacja.uruchomiona);
Po uruchomieniu powinny pokazać się dwa alerty - jeden z wartością true, a drugi z wartością false.
Podsumujmy to co już potrafimy zrobić - potrafimy zdefiniować klasę mającą kilka metod i właściwości, potrafimy też odwoływać się do nich zarówno na zewnątrz, jak i z wnętrza klasy no i umiemy tworzyć obiekty danej klasy. Zgłębimy teraz temat tworzenia klas.
Metoda definiowania klas, którą pokazałem na początku wpisu:
var NazwaKlasy = new Class({właściwości_i_metody});
To tak naprawdę jedna z dwóch metod definiowania klasy, ale niewątpliwie najpopularniejsza. Druga metoda to podanie jako argumentu, zamiast obiektu z właściwościami i metodami, innej klasy:
var NazwaKlasy = new Class(new InnaKlasa());
W tym momencie nasza klasa, będzie miała taką samą definicję jak klasa InnaKlasa.
Czasami tworzenie obiektu danej klasy wygląda następująco:
var obiekt = new jakasKlasa(argumenty);
Chodzi mi oczywiście o te argumenty - są to parametry pobierane przez klasę dla metody initialize, czyli konstruktora klasy. Dzięki zdefiniowaniu tej metody możemy wykonać jakieś operacje już przy tworzeniu obiektu. Przykładowo, jeżeli chcemy by nasza klasa wywoływała akcję podobną do działania metody uruchom, zapiszemy:
var Aplikacja = new Class({
uruchomiona: false,
initialize: function(){
this.uruchomiona = true;
},
zamknij: function(){
this.uruchomiona = false;
}
});
Dzięki temu zamiast pisać:
var TestowaAplikacja = new Aplikacja();
TestowaAplikacja.uruchom();
alert(TestowaAplikacja.uruchomiona);
TestowaAplikacja.zamknij();
alert(TestowaAplikacja.uruchomiona);
zapiszemy po prostu:
var TestowaAplikacja = new Aplikacja();
alert(TestowaAplikacja.uruchomiona);
TestowaAplikacja.zamknij();
alert(TestowaAplikacja.uruchomiona);
Oczywiście jeżeli metoda initialize będzie następującej postaci:
initialize: function(parametr){
// kod metody
}
To przy tworzeniu obiektu uwzględniamy tenże parametr metody initialize:
var obiekt = new Klasa(parametr);
Jak widać jest to łatwy sposób na wykonanie kilku operacji bez wywoływania dodatkowych metod.
Aby rozszerzyć możliwości naszej klasy możemy skorzystać z metody implement, która jako argument przyjmuje obiekt z metodami i właściwościami, jakie mają być dodane do naszej klasy:
klasa.implement({wlasciwosci_i_metody});
Pamiętajmy, że rozszerzamy KLASĘ, a nie OBIEKT KLASY.
Jest też inna metoda pozwalająca rozszerzyć możliwości klasy - dziedziczenie. W MooTools rozwiązano to za pomocą dwóch właściwości - Implements i Extends. Obie z nich podajemy przy definiowaniu klasy, a jako argument Extends pobiera nazwę klasy, natomiast Implements może pobierać, nazwy klas, obiekty i tablice obiektów i klas.
Extends pozwala nam na nadpisanie metod klasy bazowej poprzez metody klasy potomnej, jednak nadal mamy dostęp do pierwotnej wersji metody poprzez odwołanie:
this.parent();
O nim za chwilę, ale najpierw słów kilka o właściwości Implements - ona w odróżnieniu do Extends nie daje nam dostępu do bazowej wersji metody, a dodatkowo jak już wspomniałem - pozwala na rozszerzenie możliwości klasy o kilka klas/obiektów naraz.
Klasy w MooTools zachowują się w sposób analogiczny do obiektów - można je rozszerzać o nowe właściwości w dowolnym momencie, ale różnica polega na tym, że obiekty wykorzystujemy raczej do przechowywania określonych wartości pod zadanymi nazwami właściwości obiektu.
Na sam koniec tej części kursu wróćmy do odwołania this.parent(). Wspomniałem, że zapis ten daje nam dostęp w klasie potomnej do pierwotnej wersji metody w klasie bazowej. Zobaczmy więc jak wygląda to w praktyce.
Przyjmijmy, że mamy klasę Informacja z jedną metodą info:
var Informacja = new Class({
info: function(inf){
alert(inf);
}
});
Teraz na bazie tej klasy chcielibyśmy stworzyć sobie klasę potomną Info, która będzie także miała metodę o tej samej nazwie (tylko pisanej z małej litery):
var Info = new Class({
Extends: Informacja,
info: function(inf2){
alert(inf2);
}
});
Aby w metodzie info klasy Info wywołać dwa alerty jeden bezpośrednio z klasy bazowej, a drugi z klasy potomnej zapisujemy:
var Info = new Class({
Extends: Informacja,
info: function(inf, inf2){
this.parent(inf)
alert(inf2);
}
});
jak widać zwiększyła się też liczba argumentów pobieranych przez metodę info - do wywoływanej z klasy bazowej metody możemy śmiało przekazać potrzebne parametry. Po wywołaniu metody info z klasy Info zobaczymy dwa alerty z określonymi przez nas w argumentach metody wiadomościami.
Podsumowując właściwości Implements i Extends - pierwszą z nich stosujemy wtedy gdy musimy w klasie zupełnie zmodyfikować metody, a drugą wykorzystujemy w sytuacji gdy w klasie potomnej ma występować tylko nieznacznie zmodyfikowana wersja metody (a dokładniej wersja rozszerzona o kolejne funkcje) - dzięki Extends możemy zaoszczędzić w niektórych sytuacjach naprawdę sporo kodu.
Poznaliśmy w ten sposób podstawy klas w MooTools - wiemy jak stworzyć klasę, obiekty klasy oraz jak tworzyć klasy potomne i modyfikować już istniejące. W następnej części kursu rozszerzymy naszą wiedzę o klasy, które rozszerzają nasze możliwości i wtedy będziemy już gotowi by napisać nasz pierwszy plugin dla MooTools.
Komentarze do wpisu "MooTools 1.2 - programowanie obiektowe - podstawy":
1.
Bigismall napisał(a):
10 marca 2008, 08:35:32
„Podsumowując właściwości Implements i Extends – pierwszą z nich stosujemy wtedy gdy musimy w klasie zupełnie zmodyfikować metody”
Widzisz Dziudek, wydaje mi się, że „Implements” zostało stworzone po to aby dać namiastkę tego co mamy w innych obiektowych językach programowania. Chodzi mianowicie o implementowanie interfejsów. Czyli tworzymy sobie puste klasy, określając jedynie metody. To jest nasz interfejs, który różne klasy mogą implementować na różne sposoby.
Interfejsy są bardzo przydatne, podejrzewam więc że twórcy MooTools chcieli dać nam możliwość tworzenia takowych.
Ale jest to moja wizja, więc upierać się nie będę.
P.S
Ponownie życzę wytrwałości.
2.
Dziudek napisał(a):
10 marca 2008, 15:21:39
@Bigismall – być może tak jest, nie potwierdzam, nie zaprzeczam. Programiści MooTools lubią wykorzystywać rozwiązania znane z innych języków jak chociażby $lambda i times kojarzące mi się z Rubim. Choć akurat $lambda to raczej wywodzi się z języków funkcyjnych, w każdym razie widać, że autorzy tego frameworka nie pozostają obojętni na ciekawe rozwiązania z innych języków i chwała im za to :)
3.
Bigismall napisał(a):
16 marca 2008, 12:09:49
Dziudek, pamiętasz może? Był taki program/strona WWW która analizując kod JS wypisywała jedynie te klasy które są potrzebne do załączenia. Ja w obecnej chwili ładuje plik z wszystkimi klasami, a jest tego 50KB bez pluginów :| Kod jest dosyć rozbudowany i ciężko mi już określić co potrzeba, a co nie.
4.
Dziudek napisał(a):
16 marca 2008, 12:28:59
@Bigismall – oczywiście, że pamiętam o moim podstawowym narzędziu – Packito ;)
Tylko mała uwaga – ta „aplikacja” ma mały błąd, mianowicie jeżeli korzystasz ze zdarzenia DOMReady to ona i tak nie pokazuje na liście pliku window.domready, także ten plik musisz dodać sam jeżeli z jego funkcjonalności korzystasz :)
5.
Bigismall napisał(a):
16 marca 2008, 17:35:49
O to właśnie chodziło. Dzięki za podpowiedź.
6.
Michal K napisał(a):
28 marca 2008, 02:11:44
„Będzie on poświęcony temu jak MooTools 1.2 wspomaga programowanie obiektowe w JavaScript (wspomaga, bo trzeba pamiętać iż JavaScript to język z natury w pełni obiektowy).”
oj Dziudek js nie jest w pełni obiektowy :) przykładowo nie ma hermetyzacji :), mogę też narzekać na dziedziczenie to, nie jest to samo co w c++ czy java7.
Raven napisał(a):
23 maja 2008, 13:57:55
Kiedy można się spodziewać drugiej części?
8.
Dziudek napisał(a):
24 maja 2008, 05:06:39
@Michał K – [dopiero teraz zauważyłem komentarz – nie dostałem powiadomienia xD] W pełni obiektowy – chodziło mi o to, że cały JS bazuje na obiektach – nie chodziło mi o to co oferuje, bo JS ma wiele ograniczeń jak zresztą większość języków skryptowych, ale nawet banalne wywołanie alert(„test”) to w rzeczywistości wywołanie metody window.alert(„test”) ;)
@Raven – jak już wspominałem w kwietniowym wpisie – chwilowo odpoczywam od bloga technicznego, a także czekam na to co będzie w stabilnej wersji MooTools 1.2 bo muszę przyznać, że często zdarzają sie naprawdę duże zmiany… Także dalszej części kursu należy się spodziewać wtedy kiedy nadejdzie odpowiedni moment ;)
Dodaj komentarz: