Patří sem rozhraní??? ====== Principy objektově orientovaného programování ====== ===== Vztah k ostatním paradigmatům ===== Každé programovací paradigma se snaží vyřešit problém sdíleného stavu programu. * imperativní programování - výchozí způsob - stav je libovolně měnitelný a je sdílen v globálních a lokálních proměnných * funkcionální programování - "žádný sdílený stav neexistuje" - stav je neměnný, mezi tzv. "pure" funkcemi bez vedlejších účinků se posílají kopie stavu * objektové programování - stav je rozdělen na malé části a zapouzdřen logikou programu v objektech To znamená, že konkrétní hodnoty jsou uloženy jako atributy těchto objektů. Zpracování atributů spolu s celkovou komunikací s objekty probíhá pomocí kódu, který je obsažený v metodách objektů. Navenek pak program působí jako několik navzájem spolupracujících objektů, což umožňuje snadnější přenos kódu mezi různými projekty a jednodušší úpravu již existujícího kódu pomocí dědičnosti. Další výhodou je také větší zabezpečení dat díky viditelnosti atributů. Nevýhodou objektově orientovaného programování je jeho větší náročnost na paměť a výpočetní rychlost, proto se používá hlavně u moderních počítačů, kde jsou tyto nevýhody téměř neznatelné. U mikropočítačů a jednoduchých jednoúčelových strojů je však výhodnější použití strukturovaného programování. ===== Zapouzdření ===== Zapouzdření není výhradně koncept OOP. Obecně v programování znamená, že nějaké data nebo logiku schováme za restriktivním rozhraním. V OOP je tento koncept implementován třídami, kde data jsou schována v podobě privátních atributů, které můžeme manipulovat pomocí public metod. Příkladem zapouzdření je například kolekce HashMap v jazyce Java (skrývá implementaci hašovací tabulky za metodami .put() nebo .getOrDefault()). ===== Dědičnost ===== Dědičnost umožňuje tvorbu nových tříd podle již vytvořených tříd. Tyto odvozené třídy sdědí všechny public a protected atributy a metody rodičovských tříd. Odvozené třídy si mohou tato data různě upravovat nebo přidávat další. např: class Zpevak extends Clovek { zpivej(){}; tancuj(){}; } V tomto příkladu jsme vytvořili novou třídu //Zpevak//, která je odvozena od třídy //Clovek//. Objekt třídy //Zpevak// tedy může využívat všechny atributy a metody třídy //Clovek// (např. metoda //vstan()// a atribut //barvaOci//) a zároveň nově vytvořené metody //zpivej()// a //tancuj()//. Podle kritiků by se dědičnost měla používat velmi vzácně, protože vytváří problém přílišné abstrakce a hluboké hiearchie dědičnosti, ve které člověk nepozná, kde je logika skutečně implementována. Z těchto důvodů existuje nepsané pravidlo, že dědičnost by měla být hluboká pouze 1 vrstvu. (dceřiná třída nesmí být rodičovskou třídou pro jiné třídy) Na druhou stranu existují případy, kde je vícevrstvá dědičnost velmi výhodná - například při implementaci datových struktur ve standardní knihovně jazyku Java nebo ve vývoji her (hierarchie typu Entity -> Character -> Player). ==== Vícenásobná dědičnost ==== Počet rodičovských tříd je určen použitým programovacím jazykem (např. Java umožňuje pouze jednu rodičovskou třídu, C++ umožňuje více). ===== Polymorfismus ===== Umožňuje použít jednotné rozhraní pro práci s různými typy objektů. ==== Compile-time polymorfismus ==== Přetěžování metod - metoda může fungovat více různými způsoby, které se rozliší podle druhu a počtu parametrů. (funguje pouze v jazycích s ) Programovací jazyk se statickými typy ví, jaké datové typy používá, a proto umí vybrat správnou metodu při kompilaci. Příkladem je třída PrintStream v jazyce Java (implementuje System.out.println()): {{:informatika:maturita:java_printstream.png?800|}} ==== Runtime polymorfismus ==== Při běhu programu se musí zjistit, který datový typ používá a tím pádem kterou metodu volat. 2 způsoby implementace: * alespoň 2 třídy mají stejnou rodičovskou třídu * alespoň 2 třídy implementují stejné rozhraní public class OsobaGML { public abstract void prezujSe(); } public class StudentGML extends OsobaGML { @Override public void prezujSe() { System.out.println("Jdu ke skříňkám, otevřu svou skříňku, přezuji se.") } } public class KantorGML extends OsobaGML { @Override public void prezujSe() { System.out.println("Jdu do svého kabinetu, přezuji se.") } } public static void main(String[] args){ OsobaGML[] osoby = new {new KantorGML(), new StudentGML()}; // Mám pole všech osob a chci, aby se všichni přezuli. for(osoba : osoby){ osoba.prezujSe(); // Zde musí program rozlišit, jestli je konkrétní osoba kantorem nebo studentem. } } ===== Viditelnost atributů a metod ===== Nastavením viditelnosti dat můžeme určit, které části programu budou mít k těmto datům přístup. Nastavit můžeme tři základní možnosti. * private - data jsou viditelná pouze pro konkrétní objekt * public - data jsou viditelná komukoli * protected - data jsou viditelná pouze pro konkrétní třídu a odvozené třídy ===== Rozhraní ===== 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ě může abstraktní třída předepisovat doimplementování metod, pro které ona sama nemá vlastní kód, ale jen předpis abstraktní metody. ===== Design patterns (návrhové vzory) ===== Navrhují konkrétní způsoby řešení častých problémů v OOP. Tyto způsoby byly poprvé popsány v knize [[https://en.wikipedia.org/wiki/Design_Patterns#Patterns_by_type|Design Patterns]] v roce 1994. Výhody: * rychlost implementace (Nemusím vymyslet způsob řešení problému.) * komunikace v týmu (Kolega rychle pochopí, protože taky dobře zná tyto návrhové vzory-) * údržba kódu (Tyto vzory vytváří tzv. "loose coupling". To znamená, že můžu nahradit jednu část systému, aniž bych rozbil všechno ostatní.) Nevýhody: * Často vedou ke příliš komplikovanému kódu, protože byly použity, aniž by byly potřeba. Tady je seznam nejdůležitějších z každé kategorie: ==== Creational ==== Nabízí alternativní způsoby vytvoření objektů. * [[https://en.wikipedia.org/wiki/Builder_pattern|Builder]] * [[https://en.wikipedia.org/wiki/Singleton_pattern|Singleton]] ==== Structural ==== Vysvětlují, jak uspořádat objekty do větších struktur. * [[https://en.wikipedia.org/wiki/Adapter_pattern|Adapter]] * [[https://en.wikipedia.org/wiki/Decorator_pattern|Decorator]] ==== Behavioral ==== Vysvětlují komunikaci mezi objekty. * [[https://en.wikipedia.org/wiki/Iterator|Iterator]] * [[https://en.wikipedia.org/wiki/Observer_pattern|Observer]]