Hlavní obsah
Programování
Kurz: Programování > Kapitola 1
Lekce 17: Objektově orientovaný design - BONUSShrnutí: Objektově orientovaný design
Zde je přehled toho, co jsme probrali v lekci o objektově orientovaném programování.
Když programujeme, často zjišťujeme, že chceme vytvořit mnoho různých objektů, které mají podobné vlastnosti - například mnoho koček, které mají mírně odlišnou barvu a velikost, nebo mnoho tlačítek s různými popisky a pozicemi. Chceme říct "takhle obecně kočka vypadá" a pak řekneme "udělejme tuto konkrétní kočku, a tuto jinou kočku, která bude v několika ohledech podobná, a v jiných odlišná." V takovém případě chceme použít objektově orientovaný design pro definování typů objektů a vytvoření nových instancí těchto objektů.
Pro definování typu objektu v JavaScriptu musíme nejprve definovat "konstruktor". To je funkce, kterou použijeme, když chceme vytvořit novou instanci určitého typu objektu. Tady je konstruktor pro typ objektu
Book
:var Book = function(title, author, numPages) {
this.title = title;
this.author = author;
this.numPages = numPages;
this.currentPage = 0;
};
Tato funkce má jako argumenty aspekty objektu, které budou rozdílné pro každou knihu - název, autor a počet stránek. Poté nastaví počáteční vlastnosti objektu na základě těchto argumentů, pomocí klíčového slova
this
. Pokud použijeme this
v rámci objektu, odkazujeme se na aktuální instanci objektu, tedy odkaz na sebe sama. Vlastnosti musíme uložit do this
, abychom je později mohli používat.Chceme-li vytvořit instanci objektu
Book
, vyhlašujeme novou proměnnou pro její uložení, pak použijeme klíčové slovo new
, následované názvem konstruktoru a předáme argumenty, které konstruktor očekává:var book = new Book("Robot Dreams", "Isaac Asimov", 320);
Pak můžeme přistupovat k vlastnostem, které jsme uložili v objektu pomocí tečkové notace:
println("Líbilo se mi číst " + book.title); // Líbilo se mi číst Robot Dreams
println(book.author + " je můj nejoblíbenější autor"); // "Isaac Asimov" je můj nejoblíbenější autor
Na druhou stranu, zde je ukázka toho, co by se stalo, pokud bychom nenastavili konstruktor správně:
var Book = function(title, author, numPages) {
};
var book = new Book("Little Brother", "Cory Doctorow", 380);
println("Líbilo se mi číst " + book.title); // Líbilo se mi číst undefined
println(book.author + " je můj nejoblíbenější autor"); // undefined je můj nejoblíbenější autor
Pokud předáme argumenty konstruktoru, ale neukládáme je pomocí
this
, pak k nim nelze mít přístup později! Objekt na ně zapomene.Když definujeme objekty, často chceme spojit vlastnosti a chování objektu - všechny naše objekty koček by měly být schopny mňoukat() a jíst(). Takže musíme být schopni připojit funkce k definicím typu objektu, a můžeme to udělat tak, že je definujeme na tom, co se nazývá prototyp objektu:
Book.prototype.readItAll = function() {
this.currentPage = this.numPages;
println("Už máš přečteno " + this.numPages + " stránek!");
};
Je to podobné, jako kdybychom vytvářeli normální funkci, kromě toho, že ji zavěsíme na prototyp
Book
, namísto abychom ji definovali globálně. Takto JavaScript pozná, že tato funkce může být volána na jakémkoliv objektu Book
, a že tato funkce má přístup k this
knihy, na kterou je volána.Pak můžeme zavolat funkci (kterou nazýváme metodou, pokud je připojena k objektu), například takto:
var book = new Book("Animal Farm", "George Orwell", 112);
book.readItAll(); // Už máš přečteno 112 stránek!
Pamatuj, že celý smysl objektově orientovaného designu je snadnější vytváření více souvisejících objektů (instance objektů). Podívejme se, jak to vypadá v kódu:
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(); // Už máš přečteno 384 stránek!
giver.readItAll(); // Už máš přečteno 179 stránek!
tuck.readItAll(); // Už máš přečteno 144 stránek!
Tento kód vytvoří tři knihy, které jsou podobné - mají stejné vlastnosti a chování, ale zároveň se i liší. Super!
Ve skutečném světě jsou kočky a psi různé typy objektů. Takže při programování
Kočky
a Psa
zřejmě vytvoříš rozdílné typy objektů. Kočka bude mňoukat()
a pes štěkat()
. Ale zároveň budou tyto objekty podobné - oba objekty budou jíst()
, budou mít věk
, datum narození
a datum úmrtí
. Kočka i pes jsou savci, mají tedy hodně společného, i když se také zároveň odlišují.V takovém případě chceme použít myšlenku dědičnosti objektů. Typ objektu by mohl dědit vlastnosti a chování podle typu nadřazeného objektu, ale zároveň má také své vlastní unikátní prvky. Všechny
Kočky
a Psi
by mohli dědit z objektu Savci
, takže bychom pro ně nemuseli znovu vynálézat jezení()
. Jak bychom to udělali v JavaScriptu?Vraťme se k našemu příkladu s knihou, a řekněme, že
Book
je objekt typu "rodič" (anglicky "Parent"), ze kterého mají dědit dva objekty - PaperBack
a EBook
.Paperback, neboli brožovaná kniha, je typ knihy, který se od standardní knihy liší jednou věcí, minimálně v rámci našeho programu: má obrázek na přebalu (tzv. cover). Tím pádem náš konstruktor musí převzít čtyři argumenty (název, autor, počet stran, obálka):
var PaperBack = function(title, author, numPages, cover) {
// ...
}
Protože se nám nechce znovu dělat všechnu tu práci, kterou jsme dělali při vytváření konstruktoru
Book
a jeho tří argumentů - využijeme toho, že tato část kódu je stejná. Takže můžeme zavolat konstruktor Book
z konstruktoru PaperBack
, a předat mu tyto argumenty:var PaperBack = function(title, author, numPages, cover) {
Book.call(this, title, author, numPages);
// ...
};
Stále však musíme uložit i vlastnost
cover
, tedy přidat jeden řádek kódu:var PaperBack = function(title, author, numPages, cover) {
Book.call(this, title, author, numPages);
this.cover = cover;
};
Nyní máme konstruktor pro
PaperBack
, který sdílí stejné vlastnosti jako Book
, ale také chceme, aby PaperBack
zdědil jeho metody. Zde je způsob, jak říci programu, že by prototyp PaperBack
měl být založen na prototypu Book
:PaperBack.prototype = Object.create(Book.prototype);
Mohli bychom také chtít připojit chování typické pro paperback, jako je jeho hořlavost, a můžeme to tak udělat definováním funkcí prototypu. Tento kód pak napíšeme za kód, který jsme si uvedli výše:
PaperBack.prototype.burn = function() {
println("Jejda, bylo spáleno " + this.numPages + " stránek");
this.numPages = 0;
};
Takže nyní můžeme vytvořit nový paperback, přečíst si ho a pak ho spálit!
var calvin = new PaperBack("The Essential Calvin & Hobbes", "Bill Watterson", 256, "http://ecx.images-amazon.com/images/I/61M41hxr0zL.jpg");
calvin.readItAll(); // Už máš přečteno 256 stránek!
calvin.burn(); // Jejda, bylo spáleno 256 stránek!
(I když, pálit ji ve skutečnosti nebudeme, je to skvělá kniha. Ledaže bychom uvízli v ledové pustině, mrzli bychom a umírali.)
Nyní víš, jak používat objektově orientovaný design v JavaScriptu pro vytváření složitějších dat pro své programy a přitom tyto programy tvořit jednodušeji.
Chceš se zapojit do diskuze?
Zatím žádné příspěvky.