Główna zawartość
Programowanie
Kurs: Programowanie > Rozdział 1
Lekcja 17: Programowanie obiektowePrzegląd: Projektowanie zorientowane obiektowo
Poniżej jest podsumowanie tego, co już powiedzieliśmy na temat tworzenia oprogramowania obiektowego.
Kiedy tworzymy programy, często natrafiamy na sytuację w której chcemy stworzyć wiele podobnych do siebie obiektów- jak dużo kotów, które mają trochę inne rozmiary, kolory, albo wiele przycisków, z różnymi podpisami i rozmieszczeniem. Chcemy mieć możliwość by powiedzieć "to coś jest jak kot" a potem powiedzieć "zróbmy sobie kota jakiego chcemy, jeszcze jednego, i parę innych, a wszystkie będą do siebie jakoś tam podobne i jednocześnie różne od siebie". W tym wypadku, chcemy użyć techniki tworzenia programów zorientowanych obiektowo by zdefiniować typy obiektów i tworzyć nowe instancje tych obiektów.
By zdefiniować typ obiektu w JavaScripcie, musimy zdefiniować "funkcję konstruującą". To jest funkcja której użyjemy gdy będziemy chcieli stworzyć nowy obiekt tego konkretnego typu obiektów. Poniżej przedstawiam konstruktor obiektu typu
Book
:var Book = function(title, author, numPages) {
this.title = title;
this.author = author;
this.numPages = numPages;
this.currentPage = 0;
};
Funkcja bierze argumenty dla aspektów, które podobnie jak różnice między książkami-mają je identyfikować -tytuł, autor, i ilość stron. Wtedy ustawia początkową właściwość obiektu bazowaną na tych własnościach, używając wyrażenia kluczowego
this
. Gdy używamy słowa kluczowego this
w obiekcie, wtedy odwołujemy się do obecnej instancji tego obiektu: do niego samego. Własności przechowujemy w this
by upewnić się, że będą pamiętane też później.By stworzyć instancję obiektu
Book
, deklarujemy nową zmienną do przechowania go, a wtedy używamy wyrażenia new
, za którym umieszczamy nazwę konstruktora funkcji, i przekazujemy argumenty których się konstruktor spodziewa:var book = new Book("Robot Dreams", "Isaac Asimov", 320);
Możemy dobrać się do własności które przechowujemy w obiektach za pomocą kropki:
println("I loved reading " + book.title); // Uwielbiam ksiązkę Robot Dreams
println(book.author + " is my fav author"); // "Isaac Asimov" jest moim ulubionym autorem
A co jeśli byśmy źle zdefiniowali funkcję konstruktora?:
var Book = function(title, author, numPages) {
};
var book = new Book("Little Brother", "Cory Doctorow", 380);
println("I loved reading " + book.title); // Uwielbiam książkę undefined
println(book.author + " is my fav author"); // undefined jest moim ulubionym autorem
Jeżeli przekazujemy argumenty do konstruktora funkcji ale perfidnie nie określamy że przechowujemy je w
this
, wtedy nie będziemy mieli możliwości by się do nich później dobrać! Obiekt po prostu całkowicie o nich zapomni.Kiedy definiujemy typy obiektów, często chcemy powiązać własności i zachowania ze sobą- tak jak nasze koty mogą robić miau() i jeść(). Potrzebujemy więc podpiąć funkcje to naszej definicji obiektu, i możemy to zrobić poprzez definiowanie ich na czymś co zwie się prototypem obiektu:
Book.prototype.readItAll = function() {
this.currentPage = this.numPages;
println("You read " + this.numPages + " pages!");
};
Dokładnie tak jak definiujemy funkcję normalnie, poza tym że ciągniemy to z prototypu
Książki
(Book) zamiast definiować globalnie. To pokazuje jak JavaScript wie że to jest funkcja która może być wywołana na jakiejkolwiek Książce
(Book) , i że ta funkcja powinna móc się dobrać do this
tej książki, na której jest wywołana.Możemy wtedy wywołać funkcję (którą zwiemy tu metodą, gdyż jest podpięta do obiektu), w ten sposób:
var book = new Book("Animal Farm", "George Orwell", 112);
book.readItAll(); // You read 112 pages!
Całe ułatwienie programowania obiektowego to fakt, że możemy sobie zrobić wiele podobnych do siebie obiektów (instancji obiektów). Zobaczmy to w kodzie:
var pirate = new Book("Pirate Cinema", "Cory Doctorow", 384);
var giver = new Book("The Giver", "Lois Lowry", 179);
var tuck = new Book("Tuck Everlasting", "Natalie Babbit", 144);
pirate.readItAll(); // Przeczytałeś 384 strony!
giver.readItAll(); // Przeczytałeś 179 stron!
tuck.readItAll(); // Przeczytałeś 144 stron!
Ten kod daje nam trzy książki które są dość podobne do siebie - wszystkie mają te same własności i zachowania, ale są różne. Miodzio!
Jeśli teraz pomyślisz o naszym świecie, koty i psy są różnymi typami obiektów, więc prawdopodobnie stworzysz różne od siebie typy obiektów dla nich jeśli będziesz programować
Koty
i Psy
. Kot będzie mógł robić swoje miau()
, a pies będzie mógł szczekać()
. Ale jednocześnie są podobne: i koty, i psy potrafią jeść()
, oraz w obu przypadkach mają jakiś wiek
, datęUrodzenia
, i też dateŚmierci
. Oba są ssakami, co oznacza że mają wiele z sobą wspólnego, nawet gdy są równocześnie różne.W tym wypadku, chcemy użyć koncepcji dziedziczenia obiektów. Typ obiektu może dziedziczyć własności i zachowania z typu obiektu rodzica, ale wtedy ma w dodatku do cech rodzica cechy własne (nowe). Wszystkie
Koty
i Psy
dziedziczą po Ssakach
, więc nie muszą uczyć się na nowo jak jeść()
od podszewki. Jak to zrobić więc w JavaScripcie?Wróćmy do naszego przykładu książki, i powiedzmy że
Book
(książka) jest "rodzicem" typu obiekty, i chcemy mieć dwa obiekty dziedziczące z niej- Papierek
(Paperback) i Ebook
.Papierek (paperback ) jest jak książka, ale różni się od niej przynajmniej w naszym programie: ma obrazek na okładce. Nasz konstruktor więc potrzebuje pobierać cztery argumenty by przechować te dodatkowe informacje:
var PaperBack = function(title, author, numPages, cover) {
// ...
}
A teraz nie musimy robić wszystkiego co już mamy w konstruktorze
Książki
(Book) by zapamiętać pierwsze trzy argumenty - chcemy skorzystać z faktu, że kod będzie dokładnie taki sam. Możemy więc powiedzieć konstruktorowi Książki
(Book) by wywołał z konstuktora Papierka
(PaperBack), i przekazał te argumenty dalej:var PaperBack = function(title, author, numPages, cover) {
Book.call(this, title, author, numPages);
// ...
};
Wciąż potrzebujemy przetrzymywać własność
cover
(okładkę) w obiekcie, więc musimy napisać jeszcze jedną linijkę by sobie z tym poradzić:var PaperBack = function(title, author, numPages, cover) {
Book.call(this, title, author, numPages);
this.cover = cover;
};
Mamy teraz konstruktor dla naszego
PaperBack
(papierka), który pomaga w dzieleniu tych samych właściwości co Books
, ale chcemy by nasz papierek
dziedziczył jego metody. Poniżej pokazano jak to zrobić, poprzez pokazanie programowi że prototyp Papierek
(paperback) powinien być bazowany na prototypie Książka
(Book):PaperBack.prototype = Object.create(Book.prototype);
Możemy chcieć też dołączyć do papierka zachowanie, które tylko będzie on przejawiał, jak dla przykładu możliwość spalenia go: możemy tego dokonać poprzez definiowanie funkcji na prototypie. Po linii podanej wyżej dopisujemy:
PaperBack.prototype.burn = function() {
println("Omg, you burnt all " + this.numPages + " pages");
this.numPages = 0;
};
A teraz możemy stworzyć sobie nowy papierek, przeczytać go, i spalić!
var calvin = new PaperBack("The Essential Calvin & Hobbes", "Bill Watterson", 256, "http://ecx.images-amazon.com/images/I/61M41hxr0zL.jpg");
calvin.readItAll(); //Przeczytałeś 256 stron!
calvin.burn(); // Spaliłeś wszystkie 256 stron!
(Tak naprawdę to niczego nie będziemy palić, bo to fajna książka, no chyba że znajdziemy się na lodowcu i brak będzie nam źródła ciepła)
I teraz widzisz, że można tworzyć oprogramowanie obiektowe w JavaScripcie, które będzie mogło być coraz bardziej rozbudowane pod względem obliczeni i kodu-i prawdopodobnie sprawi, że nasz świat będzie lepszy.
Chcesz dołączyć do dyskusji?
Na razie brak głosów w dyskusji