Objektově Orientované Programování
Tenhle článek je reakcí na dotazy, které jsem dostal ohledně CiA.
Pokusím se objasnit co to je OOP a co si o něm myslím. Zároveň musím
předem upozornit ty, kteří tomu trochu rozumí, že jsem nikdy žádnou
knihu o OOP nečetl, v článku vycházím pouze z vlastních zkušeností a
dalších nedůvěryhodných zdrojů.
Moje (a předpokládám i mnohého z vás) první zkušenost:
Pár článků o OOP jsem přeci jen viděl a vy asi také. Dozvěděl jsem
se z nich co je to zapouzdření, dědičnost a polymorfismus. Ale to
hlavní, k čemu mi to bude, to mi vždycky nějak unikalo. Na přiložené
příklady jsem okamžitě viděl efektivnější neobjektovou alternativu a
to mi stačilo jako důkaz nepoužitelnosti OOP. Kromě toho jsem věděl,
jak gigantické bývají OO (objektově orientované) programy ve
srovnání se stejně velkými neobjektovými a myslel jsem si, že jsou i
pomalejší.
Po pár letech praxe je to docela jasné. S OOP lze napsat velmi
pěkné "kusy kódu", které jdou později snadno upotřebit v mnoha
dalších programech. Předpokladem opakovaného používání je ale jejich
univerzálnost. Když se pak použijí na jednodušší problémy, které tolik
univerzálnosti a dalších schopností nevyžadují, výsledný program je
větší a někdy i pomalejší. Zápory ale vyvažuje snadnost s jakou se OO
programy píší.
Pozorný čtenář může namítnout, že OO programy se píší snadno až
tehdy, když má programátor připravenou zásobu takových "kusů
kódu", ze kterých se dá výsledný program sestavit. Ano, nezbytným
předpokladem snadného a rychlého programování je mít za základ
nějakou knihovnu, ať už vlastní nebo cizí, a dobře se v ní vyznat.
Co to vlastně to OOP je?
Je to rozšíření jazyka, které umožňuje psát přesně takové
snadno upotřebitelné univerzální "kusy kódu" o jakých tu byla řeč. Ty
jsou ale, když to přeženu, napsány normálním jazykem, OOP je jen
"obaluje" a vnáší do programu strukturu a pořádek. Takže OOP je jen
pomůcka, to hlavní se musí napsat postaru.
OOP ale není žádná kouzelná hůlka, která za nás v programu udělá
pořádek. Syntaxe sice nutí k určitým krokům správným směrem, ale i
tak nezabrání řadě "ošklivých" věcí, které se stále dají dělat.
Důležité je myslet dopředu a psát tak, aby se dal jednou hotový kód
použít i později a jinde.
Ale teď stop. O OOP píšu jako o nadstavbě nad nějakým jazykem. Ve
skutečnosti asi nejprve vznikly čistě OOP jazyky (třeba SmallTalk) a až
po jejich úspěchu nadstavby nad zavedené neobjektové jazyky (C,
Pascal).
PRINCIPY
To byly rysy OOP, které považuji za nezbytně nutné k pochopení
významu a k úspěšnému využití OOP. Tady jsem chtěl skončit, protože
zde začínají všechny ostatní články o OOP a já bych to tak dobře
stejně napsat nedokázal. Ale pak mi přišlo nefér teď skončit,
následuje tedy popis konkrétních vlastností, které OOP používá k
dosažení výše popsaných cílů.
Třída je typ. Je to datová struktura plus funkce pro práci s
těmito daty. Instance je konkétní proměnná typu třída.
Zapouzdření je vlastnost tříd a jejich instancí. To jsou jakési black
boxy, do kterých zvenku není vidět. Řekneš instanci aby provedla to a
to a ona to udělá. Nezajímá tě jak to dokázala. Sice tam někde uvnitř
je kód, který jsi kdysi musel ty, nebo někdo jiný, napsat, ale teď se
na věc díváš zvenčí a vidíš jen povrch black boxu s několika knoflíky,
kterými vydáváš povely. Praktický význam je ten, že až ti schopnosti
třídy nebudou stačit, můžes její vnitřek totálně přepsat, navenek ale
zůstane stejná, takže ve zbytku programu se nebude muset nic měnit.
Dědičnost je vlastnost tříd. Třída může být potomkem jedné či více
jiných tříd (v pascalu jen jedné). V takovém případě zdědí datové
struktury a funkce svých předků. To se samozřejmě náramně hodí.
Polymorfismus je vlastnost instancí. Instance různých tříd mohou
zvenčí vypadat úplně stejně, uvnitř ale pracovat jinak. Typickým
příkladem je funkce "zruš se". Tu mají skoro všechny třídy a tedy i
jejich instance. Instance různých tříd ale vypadují jinak a proto se
musí i rušit jinak. Polymorfismus zajistí, že se při vydání povelu
provede správná akce v závislosti na tom o jakou instanci jde.
IMPLEMENTACE
A už jsem chtěl zase skončit, ale přišlo mi nefér vůči těm, co se
prokousali až sem, neříct něco konkrétního o implementaci výše
uvedených principů. Kdo chce programovat OO, musí znát principy, ale
taky musí vědět "co se tam děje", tedy jak jsou implementovány. Budu
se držet v obecnosti, žádná konkrétní syntaxe.
Jak už bylo řečeno výše, třída se skládá z dat a funkcí pro práci
s nimi. Datům se říká atributy, funkcím metody. Když zavoláš metodu
nějaké instance, je to jako kdybys zavolal obyčejnou funkci se
skrytým parametrem "pointer na instanci".
Jak funguje zapouzdření? V deklaraci třídy se uvádí které
atributy a metody jsou veřejné a které jsou privátní, případně další
stupně veřejnosti/neveřejnosti. Pouze s veřejnými složkami třídy se
pak dá zvenčí manipulovat. To ostatní je soukromou záležitostí třídy a
nikomu venku do toho nic není. V některých jazycích jsou všechny
atributy privátní.
Jak funguje dědičnost? Instance je složená z atributů a metod.
Dvě instance stejné třídy mají v atributech různá data, ale jejich
metody jsou stejné, takže když vytvoříš instanci, pouze se někde
naalokuje kus paměti pro atributy. Třída, která je potomkem jiné
třídy, zdědí její atributy a metody. V praxi to znamená pouze to, že
se každá instance zvětší o zděděné atributy. Děděné metody jsou v
paměti jen jednou, společné pro předka i potomka.
Jak funguje polymorfismus? Nejprve je třeba vyřídit jednu
technickou záležitost. Každá proměnná má svůj typ. Proměnná P může
být třeba pointer na instanci třídy T1. Ale přitom může ukazovat na
instanci třídy T2, která je potomkem T1. Taková situace je běžná a
naprosto legální, všechno co lze provést s T1 lze provést i s T2,
takže můžeme být bez obav. Přijdeme pouze o možnost pracovat s
atributy a metodami, které má T2 navíc oproti T1. Ale vlastně
nepřijdeme! Skoro každá instance totiž má skrytý atribut, který
udává její SKUTEČNÝ typ, její třídu. Metody se pak dělí na statické a
virtuální, přičemž o tom co se zavolá při volání statické metody
rozhoduje typ proměnné, u virtuálních metod rozhoduje typ instance.
Až budeme chtít zrušit instanci, na kterou ukazuje pointer P,
zavoláme její metodu "zruš se". Pokud by byla statická, zavolala by
"zruš se" třídy T1 a zrušila pouze část instance. Jelikož je to metoda
virtuální, podívá se na skutečný typ instance a zavolá "zruš se"
třídy T2. Pomocí virtuálních metod tak můžeme využít i vlastnosti T2,
kterými se liší od T1.
Slovníček s dalšími pojmy:
Constructor a destructor jsou speciální metody volané při
vytváření a rušení instance. V C++ se volají automaticky, v Object
Pascalu ručně.
Late binding je rozhodování se jakou metodu zavolat až za běhu
programu. Tedy zjištění typu instance a zavolání metody toho typu.
VMT aneb Tabulka virtuálních metod obsahuje pointery na virtuální
metody dané třídy. Pointery se tedy neskladují uvnitř instance, tam
je pouze odkaz na tabulku virtuálních metod společnou pro celou
třídu. Tento odkaz je zároveň oním skrytým atributem typu instance.
Samozřejmě to může být implementováno i jinak, ale nevím o žádném
jazyce, který by tak činil.
SYNTAXE
Na konec by to chtělo vysvětlit syntaxi. Ale to by bylo trochu
delší povídání. Já vím, je to nefér takhle skončit, ale popisů syntaxe
najdete spoustu v příslušných knihách a manuálech.
ZÁVĚREM
Před pár lety bylo všechno ještě v plenkách, člověk se mohl
podívat na jakýkoliv program a říct si, udělám lepší. To byla panečku
motivace. Za tu dobu se ale úroveň dost zvedla, už není snadné
trumfnout profesionální programy nebo finská dema. Začínající
programátoři tak přišli o jeden důvod proč programovat, dostat se na
špičku trvá roky a dá to spoustu práce. Ale zas to stojí za to... :) A
beztak je to skvělá zábava, ať už nahoře nebo dole. No nic.
Kdo teď chce začít, asi pošilhává po OOP (pokud dočetl až sem). Ok,
ale OOP je jen pomůcka. Co vlastně musí dobrý programátor umět?
- schopnost nacházet efektivní řešení problemů
- přístup k technickým informacím
- základní syntaxe jazyka
- přidaná OOP syntaxe (pokud nejde o čistě OOP jazyk)
- principy OOP (které jsem se snažil dostat do tohoto článku)
Poznámka k terminologii:
Třídám se někdy říká objekty. Instancím se někdy říká objekty. A
tak dál, záleží na okolnostech.
Dee