Základní principy a pojmy objektově orientovaného programování

Autor: Joker
Tato kapitola slouží jako teoretický úvod a vysvětlení základních pojmů, zatím ještě nebudeme programovat.

Objektově orientované programování (OOP) je programovací paradigma. Rozdíl oproti procedurálnímu programování (pozn.: Kromě procedurálního a objektového existují i další paradigmata, ale těmi se nebudeme zabývat) nespočívá jen v psaní kódu jiným způsobem, ale v uvažování jiným způsobem. Cílem OOP je vytvářet malé, relativně samostatné a v různých aplikacích opakovaně použitelné jednotky (což, jak uvidíme níže, jsou právě „objekty“).

Proč programovat objektově?

Jako výhody se uvádějí snazší a rychlejší vývoj aplikací, snazší údržba a menší chybovost. Nevýhodou je, že správa objektů zabere určité systémové prostředky, takže dokonale napsaný objektový program bude pomalejší, než dokonale napsaný procedurální program. Zastánci objektového programování ale argumentují, že prakticky žádná reálná aplikace nebude dokonale napsaná, přičemž v OOP je díky jeho vlastnostem snazší se té dokonalosti přiblížit, čímž se eliminuje ta výkonová nevýhoda.

V každém případě ale v dnešní době u mnoha aplikací roste důležitost snadné údržby a rozšiřitelnosti na úkor výkonové optimalizace. Zatímco výpočetní výkon často lze jednoduše (třeba i jen posunutím šoupátka v administraci) a levně (ve srovnání s cenou práce programátora) navýšit posílením hardwaru, neschopnost opravovat chyby aplikace a přidávat nové vlastnosti může být fatální.

Základní pojmy


Objekt a jeho vlastnosti

Takže, co to vůbec je ten „objekt“? Objekt je (v programování) soběstačná entita, která obsahuje data a funkčnost (volně parafrázováno odsud). Fajn… a to znamená co? Představte si výrobu v nějaké firmě. Obecně bychom ji mohli popsat tak, že tam jsou různé entity (budova, zaměstnanec, stroj, …), každá z nich realizuje nějaké konkrétní funkce a celý proces výroby jsou vlastně interakce mezi těmi entitami (zaměstnanci komunikují spolu navzájem a se stroji, stroje přetvářejí materiál a komunikují se zaměstnanci, atd.) Přitom ty entity jsou do jisté míry soběstačné, můžeme třeba vyměnit stroj za jiný, přeřadit zaměstnance na jinou práci, a podobně. Podobně to je v objektově orientované aplikaci: Ty entity jsou objekty, činnost aplikace spočívá v interakci mezi nimi a objekty by měly být natolik uzavřené a soběstačné, aby stejný objekt šel použít i jinde (pokud tam potřebuji stejnou funkčnost) a naopak objekt mohl v aplikaci být nahrazen jiným (pokud ten jiný lépe vyhovuje požadavkům).

Programátorské objekty, podobně jako ty reálné, popisujeme jejich vlastnostmi (viz vtip: Proč je slon velký, šedý a vrásčitý? Protože je to slon, kdyby byl malý, bílý a hladký, byl by to Aspirin.) Ty můžeme rozdělit na dva druhy: Jaký je (v případě slona z vtipu velký, šedý, vrásčitý - v programování jsou to data) a co dělá neboli chování (slon dýchá, chodí, pije, atd. - v programování jsou to funkce). V OOP ten první druh vlastností (data) nazýváme atributy a druhý druh vlastností (funkčnost) jsou metody.

Když to srovnáme s procedurálním programováním, tam máme data (třeba proměnné jsou data), dokonce můžeme sdružovat podobná data (třeba do pole), ale nemůžeme sdružit data a funkce. Nemůžeme říct: „Tato sada dat patří k této skupině funkcí“. V tom se základní rozdíl mezi procedurálním a objektovým programováním.

Třída a instance

Začněme opět analogií z reálného světa, podívejte se na následující obrázek:

Pravděpodobně řeknete, že jde o obrázky tří telefonů. Ale jak to, že každý z nich je telefon a přesto se podstatně liší od těch zbývajících? Je to proto, že telefon není jeden konkrétní přístroj, ale jakýkoliv přístroj, který splňuje určité vlastnosti (umí realizovat a přijímat telefonní hovory). A právě to je třída objektů.

Třída je množina objektů s určitými vlastnostmi. Přitom samotná třída nedefinuje nějaké konkrétní objekty té třídy, jen udává, jaké vlastnosti bude mít každý objekt té třídy (podobně představa o tom co je telefon může existovat i kdyby všechny existující telefony zanikly).

Naopak instance je konkrétní objekt určité třídy. Tedy ty konkrétní telefony vyobrazené výše jsou instance telefonu. Třída může například definovat, že každý telefon má nějakou barvu (tedy třída Telefon bude mít atribut Barva). Instance pak atributu přiřadí konkrétní hodnotu, například na obrázku výše telefon vlevo je černý.

Instanční a třídní vlastnosti

Jak jsme si výše ukázali (s barvou telefonu), třída definuje, jaké vlastnosti bude mít její instance (a instance pak určí konkrétní hodnoty atributů). Abychom mohli zjistit barvu telefonu, musíme mít na mysli nějaký konkrétní telefon (instanci), obecný koncept telefonu (třída) žádnou konkrétní barvu nemá. Kromě toho se ale někdy může stát, že má nějakou vlastnost samotná třída. Řekněme, že bychom pro nějaké účely chtěli telefon reprezentovat symbolem ☎ a tuto informaci chceme promítnout do třídy. Zjevně nejde o vlastnost instance, protože symbol vyplývá z příslušnosti ke třídě a můžeme ho zjistit i kdyby neexistoval žádný konkrétní telefon (instance). Jde tedy o vlastnost třídy. Třídní vlastnosti mohou být obojího druhu, tj. atributy třídy a metody třídy. V mnoha programovacích jazycích, včetně PHP, se třídní vlastnosti nazývají statické, tedy statické atributy a statické metody.

Dědění a skládání

Skládání je celkem jednoduchý koncept: Objekty lze skládat. Abychom se odpoutali od telefonů, představme si třídu Bod (v rovině), její atributy budou souřadnice X a Y. A budeme chtít udělat třídu Kruh. Kruh je určený středem a poloměrem, přičemž střed je bod, takže atribut Střed bude objekt typu Bod.

Dědění je také intuitivní: Často se stává, že objekt patří do určité třídy, ale sama ta třída patří pod další, obecnější třídu. Například bychom měli ve firmě třídu Osoba, kdy všechny osoby mají určité společné údaje (třeba jméno a adresu), ale pak se člení na zaměstnance, dodavetele a klienty a každý typ osoby má nějaké svoje dodatečné údaje. Zde se právě uplatní dědění: Můžeme vytvořit třídu Zaměstnanec, která bude odvozená od třídy Osoba. V tom případě se třída Zaměstnanec stane specializací třídy Osoba a naopak třída Osoba je zobecněním třídy Zaměstnanec. Třída Zaměstnanec zdědí vlastnosti třídy Osoba a může k nim přidat své vlastní. Dědění není omezené na jednu úroveň, od odvozené třídy mohou být odvozené další třídy. K jedné třídě také může existovat libovolný počet odvozených tříd (které od ní dědí), ale obráceně to v PHP neplatí, jedna třída může dědit jen od jedné jiné třídy.

Můžeme si všimnout, že dědění by teoreticky šlo nahradit skládáním: Místo dědění si můžeme objekt dané třídy vložit a dosáhneme podobného výsledku. Co je vhodnější záleží na situaci a účelu.

Při návrhu dědičnosti v aplikaci je také nutné dát pozor, že některé vztahy zobecnění-specializace z reálného světa není vhodné modelovat stejným vztahem (dědičností) i v aplikaci. Například čtverec je v matematice speciální případ obdélníka. Třída Obdélník může bez problému mít dvě metody pro změnu šířky či výšky (prodlouží či zkrátí příslušné dvojice stran). Když třídu Čtverec odvodíme od třídy Obdélník, zdědí i tyto dvě metody, které ale pro čtverec nedávají smysl (u čtverce není možné změnit jen šířku nebo jen výšku tak, aby výsledek byl pořád čtverec). Popsaný problém se nazývá Problém čtverce a obdélníka či Problém kruhu a elipsy (anglická Wikipedie, zmínka v diskusi).

Viditelnost vlastností

Některé vlastnosti objektu potřebuje objekt mít kvůli svému internímu použití, ale je nežádoucí, aby je používal někdo „zvenku“ (například PIN své platební karty potřebujete znát, ale asi ho nebudete sdělovat každému na potkání). Proto lze vlastnosti rozdělit na veřejné (public), které lze volat i „zvenku“ (tzn. například vytvořím si instanci objektu a zavolám jeho metodu), a soukromé (private), které mohou používat jen jiné metody téhož objektu. Soukromé vlastnosti se navíc ani nezdědí do odvozených tříd. Proto existuje ještě třetí úroveň, chráněné (protected) vlastnosti, které se podobají soukromým, ale dědí se do odvozených tříd.

Zapouzdření

Koncept zapouzdření souvisí s výše zmíněnou viditelností a má také analogii v reálném světě: Například televizory mívají v manuálu popsané, že určité tlačítko zesílí (resp. ztlumí) zvuk. Moderní televizor nejspíš mezi stiskem tlačítka a změnou hlasitosti provede spoustu skrytých (v naší programátorské analogii by byly private, soukromých) procesů, o kterých uživatel vůbec neví. Televizor Tesla z 80. let má také tlačítka pro změnu hlasitosti, ale docílí toho nejspíš úplně jiným postupem. Uživatel přesto dokáže funkci ovládat na obou televizorech, protože nepotřebuje znát, jakým postupem televizor změnu hlasitosti provedl, stačí mu vědět, že určitý ovládací prvek zařídí změnu hlasitosti.

Analogicky fungují objekty v objektovém programování: Uživateli objektu by mělo stačit znát pouze veřejné vlastnosti objektu a jejich význam.

Například bychom měli třídu Osoba s metodou, která vrátí věk osoby. K použití metody stačí vědět, že vrátí věk osoby. Skutečná implementace může být třeba taková, že v datech osoby je rodné číslo, z něj metoda získá datum narození a podle něj určí věk. Později začneme evidovat i cizince, kteří nemají rodné číslo, ale místo něj známe přímo datum narození. Upravíme tedy strukturu třídy Osoba a implementaci metody na zjištění věku (poznámka: Místo změny původní třídy bývá vhodnější vytvořit novou odvozenou třídu). Objekt se změnil, ale při pohledu „zvenku“ je jeho použití pořád stejné. Dopady změn zůstaly díky zapouzdření izolované jen uvnitř objektu.


Správcem webu Péhápko.cz je Joker, mail zavináč it-joker tečka cz. Informace o autorských právech a možnostech použití obsahu viz Autorská práva
Přihlášení