Remove ads
paradigma počítačového programování založené na konceptu objektů From Wikipedia, the free encyclopedia
Objektově orientované programování (zkracováno na OOP, z anglického Object-oriented programming) je v informatice specifické programovací paradigma, které ho odlišilo od původního imperativního. Kód je v objektovém programování přidružen k datům (metody jsou zapouzdřeny v objektech), což umožňuje snadnější přenos kódu mezi různými projekty (abstrakce a zapouzdření). Propojení umožnilo zavést dědičnost, ale kvůli zjednodušení si vyžádalo zavedení polymorfismu.
Některé z těchto vlastností jsou pro OOP unikátní, jiné (např. abstrakce) jsou běžnou vlastností i jiných vývojových metodik. OOP je někdy označováno jako programátorské paradigma, neboť popisuje nejen způsob vývoje a zápisu programu, ale i způsob, jakým návrhář programu o problému přemýšlí.
Základním paradigmatem OOP je snaha modelovat při řešení úloh principy reálného světa v počítači pokud možno jedna ku jedné. V praktickém životě otevíráme dveře pořád stejně, bez ohledu na to, zda jsou dřevěné nebo laminované, zda mají kukátko, bezpečnostní vložku nebo řetízek navíc. Stejně tak se můžeme dívat na televizi, přepínat programy a docela dobře ji ovládat, přestože nevíme vůbec nic o principech jejího fungování. Analogicky při vývoji složitých informačních systémů mohou vývojáři používat již vytvořené komponenty, podle potřeby si je trochu upravit nebo je používat jako stavebnici pro sestavování důmyslnějších a složitějších objektů.
Existuje velké množství programovacích jazyků umožňujících objektově orientované programování, např. Perl, Smalltalk, Java, C++, Object Pascal, C#, Visual Basic .NET, Progress OpenEdge, Lisp, PHP, Python, Ruby, Go, Rust, D, Swift
Tyto jazyky můžeme rozčlenit do mnoha skupin, jako např.
Kromě vlastních implementací objektů v nějakém programovacím jazyce, existuje i obecná teorie, jež se objekty a jejich vlastnostmi zabývá.
Třída je základním obecným pojmem klasifikace, jak při návrhu uspořádávat informace do smysluplné entity. Základním pojmem je objekt, instance třídy, jako konkrétní případ realizace předpisu. Objekt si „pamatuje“ svůj stav (v podobě dat čili atributů) a zveřejněním některých svých operací (nazývaných metody) poskytuje rozhraní, jak s ním pracovat. Při používání objektu nás zajímá, jaké operace (služby) poskytuje, ale ne, jakým způsobem to provádí – to je princip zapouzdření. Jestli to provádí sám nebo využije služeb jiných objektů, je celkem jedno. Vlastní implementaci pak můžeme změnit (např. zefektivnit), aniž by se to dotklo všech, kteří objekt používají.
Abstrakce objektu, která v architektuře programu podchycuje na obecné úrovni podstatu všech objektů podobného typu, se nazývá třída. Třída je předpis, jak vyrobit objekt daného typu. Například sousedka (chápejme ji jako objekt) má nějaké jméno, je nějak vysoká, umí chodit a umí mluvit. Totéž platí i pro mne. Mohu tedy při modelování těchto dvou objektů, sousedky a mě, abstrahovat od nepodstatných dílčích odlišností a díky této abstrakci vytvořit obecnou třídu Člověk, která bude mít atributy jméno a příjmení (obojí je nějaký řetězec znaků) a metody chodit a mluvit.
Při vytváření objektů pro chod programu, které budou odpovídat zmíněným dvěma reálným objektům, je třeba vytvořit dvě různé instance třídy Člověk, pro každý modelovaný reálný objekt jednu instanci (tedy jedna instance já a jedna sousedka). Hodnoty atributů jméno a příjmení se pochopitelně v našem případě budou lišit, nicméně obě instance jsou schopny chodit a mluvit díky tomu, že jsme tyto schopnosti obecně přiřadili třídě Člověk.
Představme si dále, že můj soused je svářeč. Stejně jako moje sousedka má jméno, příjmení a umí chodit, mluvit, navíc ovšem umí svářet. Při modelování můžeme využít toho, že svářeč má všechny vlastnosti třídy Člověk a něco navíc. Vytvořme třídu Svářeč jako potomka třídy Člověk. Třída svářeč tímto dědí všechny atributy i metody třídy Člověk (nemusíme je v kódu znovu psát a budeme je upravovat na jediném místě), navíc bude mít metodu svařit.
Metoda svařit může mít například dva parametry (argumenty), prvníKusKovu a druhýKusKovu, a návratovou hodnotu jedenKusKovu. Vím, že když dám sousedovi svářeči dva kusy kovu a požádám o jejich svaření, dostanu je zpátky jako jeden kus kovu a nemusím se starat o to, jak to dokázal. Stejně to bude fungovat v programu. Objekty si mezi sebou mohou posílat zprávy, v našem případě zpráva znamená, že jeden objekt spustí metodu svařit jiného objektu a využije vrácenou hodnotu (odpověď na zprávu). Tomuto způsobu komunikace mezi objekty, která skrývá konkrétní implementaci a stará se jen o zprávy, se v objektově orientovaném programování říká zapouzdření.
Představme si nyní, že potřebujeme vytvořit komplexnější model světa, ve kterém se já od své sousedky začnu lišit. Já umím programovat a ona umí účtovat. Protože nám zůstaly různé společné vlastnosti, ponechme původní třídu Člověk a vytvořme dvě třídy Programátor a Účetní, obě odděděné od třídy Člověk. Nyní však v modelu světa nebude existovat žádná instance třídy Člověk, budou existovat jen instance potomků třídy Člověk, tedy tříd od Člověka odděděných. Pokud skutečně chceme, aby v našem modelu existovali pouze svářeči, programátoři a účetní, ale žádní obecní lidé, kteří by nespadali ani do jedné z těchto skupin, lze označit třídu Člověk jako abstraktní třídu, tedy takovou, od níž nelze tvořit žádné instance.
Děděním lze nejen rozšiřovat repertoár metod o další, ale i „měnit“ dosavadní zděděné: Například třída Starý_člověk může překrýt (angl. overriding) původní metodu chodit() poděděnou od Člověka svou vlastní implementací a chodit() bude s použitím hole: Sám už tedy jinak než o holi nechodí. Přitom si stále, např. pomocí syntaktické konstrukce zvané tečková konvence, na původní metodu Člověk.chodit() může vzpomenout, má přístup k metodám svých předků.
Jiný způsob, jak upravit nebo rozšířit možnosti (nejen zděděné) je přetěžování metody (angl. method overloading): Například Akrobat je Člověk, který umí nejen normálně chodit() po nohou, ale navíc si doplnil také schopnost volanou chodit(po_rukou). Je na volbě Akrobata, jaký vstup pro svou metodu použije, a podle toho se pak zavolá právě ta jediná odpovídající ze všech přítomných implementací této metody. Rozdíl zde může být buď v počtu předaných parametrů volané metodě, a pak je rozdíl, jestli se vozíme autem jezdit(Vozidlo auto), nebo jestli jedeme autobusem po lince 183 jezdit(Vozidlo autobus, Linka číslo): jde o dvě různé přetížené metody. Anebo zda pro řízení škodovky voláme metodu řídit(škoda) sice se stejným počtem vstupů, ale předáváme různé typy pro metody: řídit(Automobil název) a řídit(Firma název), to jsou dvě různé přetížené metody, obě Člověkovi dostupná zároveň.
Naopak, obě volání jezdit(auto) a jezdit(motorka) použijí stejnou metodu jezdit(Vozidlo vozidlo), nejde o přetížení metody, protože se v obou případech jedná o stejný počet vstupů a i stejný typ vstupu Vozidlo. Ne že by takové ježdění nebyl rozdíl, ale ten už se při takto postavené třídě musí řešit uvnitř metody, rozvětvením běhu programu.
Prvním stupněm řešení je například do objektu zavést dědění: Prohlásit Vozidlo za abstraktní třídu, její metodu jezdit() také za abstraktní, a do odděděných metod jezdit() potomků Automobil a Motocykl přenést jen příslušné větve kódu: Jednou z výhod dědění je právě eliminace složitých podmínek pro větvení.
Jiná možnost je opravdu přetížení metody, kdy se původní obecná metoda jezdit(Vozidlo vozidlo) Člověku ponechá, navíc ale lze dopisovat specifičtější metody jezdit(Autem auto) a jezdit(Na_motorce motorka). Jestli jsou všechny tyto tři metody přítomny už přímo ve třídě Člověk, nebo přibudou další až v odděděné třídě je jedno: řidič je vidí všechny, z jeho pohledu je metoda přetížená, tedy si může vybírat.
Někdy se rodičovská metoda, třeba chodit(), nejen přetěžuje, ale navíc ještě zcela úmyslně překrývá: Třeba zmiňovaný Akrobat se naučil chodit po laně, proto je pro něj žádoucí při volání metody chodit() nejdříve zkusit svou novou schopnost, a až pak použít obecnější chodit() od předka. Nejdříve se ověří, zda Akrobat je_na_laně, podle této podmínky se buď interně zavolá chodit(po_laně), nebo se výslovně zavolá ona zděděná ale právě zakrývaná metoda parent.chodit() od předka.
Akrobat nemusí být odděděn od Člověka ale třeba od Atleta a ten teprve od Člověka. Potom když Akrobat volá metodu předka parent.chodit(), nemusí to znamenat chodit po zemi jako u Člověka, ale třeba chodit po kladině: Metody předků se volají po jednom, zpětně ve sledu dědění, například: Akrobat.chodit() (po laně); když neplatí je_na_laně, zavolá Atlet.chodit() (po žíněnce). Když platí je_na_žíněnce, na volání samotné Člověk.chodit() (po zemi) se nedostane, protože byla splněna jedna z podmínek v překrytých metodách ve sledu dědění.
Obecně se při překrývání může ověřovat nějaká zadaná podmínka, zde prostředí, nebo před zavoláním metody předka zařídit inicializaci, vrácení prostředků systému apod. Podobná konstrukce je podstatná pro destruktor, někdy se používá i s konstruktory.
Zjistíme, že programátor umí psát na počítači a účetní také. Intuitivně cítíme, že nebudou mít mnoho dalších společných schopností a navíc tuto dovednost může mít napříč povoláními leckdo, proto nemá smysl tvořit třídu na způsob ČlovekPracujícíSPočítačem a od ní dědit Programátora a Účetní, ale je výhodnější například vytvořit rozhraní SchopenPsátNaPočítači
s požadavkem na metodu napišNaPočítači() a upravit třídy Programátor a Účetní tak, aby toto rozhraní implementovaly, tedy předepsanou metodu, a to každý po svém. V definici rozhraní nemůže být obsažen kód (implementace) dané metody, ale všechny třídy, které toto rozhraní implementují, musí být schopny se s příkazem napišNaPočítači() nějak vypořádat.
Obdobně i již zmiňovaná abstraktní třída může předepisovat doimplementování metod, pro které ona sama nemá vlastní kód, ale jen předpis abstraktní metody.
Další důležitou vlastností objektů je polymorfismus. Stejná zpráva může být poslána od různých nebo různým objektům. Lze rozlišit, zda jde o polymorfismus
Zapouzdření v objektech znamená, že k obsahu objektu se nedostane nikdo jiný, než sám vlastník. Navenek se objekt projeví jen svým rozhraním (operacemi, metodami) a komunikačním protokolem.
Představte si sekretářku a ředitele jako dva objekty. Sekretářka umí rozhraní SchopenPsátNaPočítači
, kde je např. operace napsatDopis
, ale ředitel ho nemá (není to jeho starost). Ale může mít operaci napsatDopis
, protože může požadavek předat jinému objektu – sekretářce. Udržování odkazů na jiné objekty se říká skládání objektů a využívání jejich služeb delegování.
Skládání objektů je jednou z nejdůležitějších vlastností objektového datového modelu. Je o dost důležitější než dědičnost. I dědičnost lze v OOP realizovat pomocí skládání objektů.
A konečně zodpovědnost objektu je to, co objekt umí, o co se stará. Objekt by neměl umět sám příliš mnoho a nemusí to dělat sám (viz skládání objektů). Znakem kvalitního návrhu softwaru je to, že třídy v projektu obsahují pokud možno atomické metody, které řeší pouze jeden konkrétní problém.
Seamless Wikipedia browsing. On steroids.
Every time you click a link to Wikipedia, Wiktionary or Wikiquote in your browser's search results, it will show the modern Wikiwand interface.
Wikiwand extension is a five stars, simple, with minimum permission required to keep your browsing private, safe and transparent.