====== AP4, IN4 Objektově orientované programování ====== ===== Zadání ===== (základní pojmy OOP, zapouzdření, dědičnost, polymorfizmus, objektové programování v imperativním jazyce, spolupráce objektů. Událostmi řízené programování. Výjimky) ===== Úvod ===== Objektově orientované programování je metoda vytváření software. OOP vzniklo v 70. letech 20. století, oproti strukturovanému programování nedekomponuje problém shora dolů (rozdělení na menší celky, viz [[home:prog:ap3]]), ale vytváří stavební objekty, pomocí nichž se program modeluje (styl zdola nahoru). Lépe odpovídá uspořádání skutečného světa. Mezi OO programovací jazyky patří Smalltalk, C++, Java, Python apod. Příklady v této sekci jsou v syntaxi jazyka Java pokud není uvedeno jinak. ===== Objektový model ===== **Objekt** - má svůj obraz v reálném světě, má vlastnosti a chování reprezentovány atributy a metodami. Objekt navenek zpřístupňuje rozhraní, pomocí kterého se s objektem pracuje. Veřejné rozhraní objektu je dáno veřejnými metodami objektu. **Třída** je typ objektu, **instance** je konkrétní výskyt objektu. Příklad ukazuje vytvoření instance třídy Person: Person kuba = new Person("Kuba"); //novy objekt kuba je instanci tridy Person Když je objekt vytvářen, volá se také automaticky speciální funkce třídy nazývaná **konstruktor** (užívaná k inicializaci členů třídy). Jednotlivé **Atributy** a **metody** jsou vlastnosti instancí objektu, nikoliv tříd. kuba.name //atribut instance uchovavajici jmeno kuba.getName() //metoda vracejici jmeno Speciálním případem třídy je **abstraktní třída**. Je to třída která obsahuje nejméně jednu //abstraktní metodu// a z této abstraktní třídy není dovoleno vytvářet instance. Teprve třída, která je jejím potomkem (viz dále) a implementuje všechny abstraktní metody, může vytvářet instance. Neabstraktní metody abstraktní třídy jsou společné všem potomkům. public abstract class SqlOperations { abstract void sqlConnect(); //tato metoda bude rozdilna pro Oracle, MySQL... } public class MySqlOperations extends SqlOperations{ void sqlConnect() { //implementace podle potreby } } **Interface (rozhraní)** je množina hlaviček metod, které mohou být implementovány třídou. Pokud třída implementuje rozhraní, musí doimplementovat všechny jeho metody. Pokud tedy existuje rozhraní public interface ElectricalDevice { public void switchOn(); public void switchOff(); } a nějaká třída jej implementuje, můžeme si být jisti, že instance dotyčné třídy obsahují metody switchOn() a switchOff(). V C++ interface není. if (microwave instanceof ElectricalDevice) { //trida Microwave implementuje ElectricalDevice microwave.switchOn(); } V některých jazycích (Java, platforma .NET) se automaticky stará o destrukci nepotřebných objektů **garbage collector**. Objekty jsou rušeny, jakmile na něj neexistuje žádný odkaz (např. při konci bloku, kde byl objekt definován, nebo přiřazením hodnoty odpovídající //null//). Při zániku objektu je volána automaticky speciální funkce **destruktor**. ===== Koncepty OOP ===== Objektové programování je charakterizováno především následujícími koncepty: * **Zapouzdření** - objekt, se kterým pracujeme, je černá skřínka s rozhraním, komunikujeme s ním pomocí rozhraní, nemůžeme mu sahat dovnitř a od jeho vnitřní implementace se abstrahujeme. Souvisí to s přístupovými právy jednotlivých tříd, atributů a metod (v Javě //public, protected//, implicitní práva, //private//). Atributy by měly být privátní (jinak porušení zapouzdření), přístup k nim by měl být povolen pouze přes metody (viz Spolupráce objektů). Příklad: public class Person(){ private String personName; public void changePersonName(String newName){ //tato metoda umoznuje kontrolu jmena pred jejim prirazenim atributu //k samotne personName neni z vnejsku tridy pristup if (allowNewName(newName)) { personName = newName; } } } * **Dědičnost** - pomocí dědičnosti se generuje hierarchie tříd. Potomci přebírají všechny vlastnosti z rodičovské třídy. Poté mohou rozšiřovat funkčnost bez zasahování do kódu rodiče (//overriding// - překrytí, předefinování rodičovských metod + vytváření vlastních). Dědičnost odpovídá vztahu //generalizace specializace// (automobil -> nákladní automobil lze dědit, protože nákladní automobil //je// speciální případ automobilu, ovšem bod -> bod+poloměr dědit nelze, protože kruh není speciální případ bodu). V Javě je možné, aby třída byla přímým potomkem pouze jedné třídy. * **Polymorfismus ** - stejně pojmenovaná metoda se může chovat různě v různých případech Obecně rozlišujeme 3 druhy polymorfismu - objektový polymorfismus - v objektovém programovacím jazyku pod pojmem polymorfismus rozumíme to, že dva objekty rozšiřující třídu různým způsobem implementují stejnou abstraktní metodu **(1)** - překrytí(override) - objekt přetěžuje(znovu definuje) poděděnou metodu **(2)** - pretížení (overload) - stejně nazvaná metoda má stejnou obecnou funkcionalitu, ale může pracovat s různými parametry (např. zásobník.push(X) s parametry int X, bool X, string X bude fungovat vždy jako zásobník) **(3)** abstract class Zvire(){ public Zvire(){} abstract void makeNoise(); public void runAway(){ System.out.print("Zvire utika pryc."); } } public class Kocka() extends Zvire{ //Kocka dědí metody třídy Zvire, jde o dedičnost public Kocka(){ } public void makeNoise(){//**(1)** System.out.print("Mnau mnau."); } } public class Ptak() extends Zvire{ public Ptak(){} public void makeNoise(){//**(1)** System.out.print("Pip pip."); } @Override public void runAway(){ //**(2)** System.out.print("Zvire odletlo pryc."); } public makeNoise(string zvuk){ //**(3)** System.out.print("Pip pip."+zvuk); } public makeNoise(int times){ //**(3)** System.out.print("Pip pip "+times.toString()+" krát"); } } ===== Spolupráce objektů ===== Pokud objekty implementují rozhraní, tak z vnějšku s tímto objektem komunikují ostatní objekty pomocí rozhraní. Spolupráce objektů je úzce svázaná s [[home:prog:ap14|Objektově orientovaným návrhem]]. V návrhu se definují vazby mezi jednotlivými třídami, tj. volání metod mezi třídami, přistupování k atributům tříd atd. Pokud je dobře provedený návrh, tak je možné z tohoto návrhu rovnou vygenerovat balíčky, rozhraní a třídy včetně metod a atributů a programátor pak jen naimplementuje jednotlivé metody. Funguje to podobně jako volání metod v rámci jedné třídy - vytvoříme si instanci třídy (nebo použijeme vhodnou existující), zavoláme metodu a dostaneme návratovou hodnotu(pokud je void, tak jen provede kód a nevrátí nic). Samozřejmě je třeba myslet i na výjimky. Většina jazyků již má hotové nejrůznější balíčky objektů, které můžeme použít při běžné práci - například při komunikaci s databází, tvorbu GUI atd. ===== Výjimky ===== Reagují na chybu. Měly by se používat výhradně k ošetření výjimečných situací, nejsou standardní prostředek řízení programu. V Javě se výjimky dědí stejně jako ostatní třídy, programátor může vytvářet vlastní. Rozlišují se //hlídané// a //nehlídané// výjimky: * **Hlídaná výjimka** - pokud může vzniknout, musíme na ni zareagovat, reagují na věc, kterou programátor nemůže ovlivnit, chybu okolního prostředí. V Javě potomci třídy Exception. Příklady: IOException, CertificateExpiredException... * **Nehlídaná výjimka** - taktéž //běhová, runtime// výjimka. Označují chybu vzniklou kdekoliv v kódu, reagují na chybu programátora (i v případě nekontrolování vstupu uživatele). Typicky se z nich nelze zotavit. V Javě potomci třídy RuntimeException. Příklady: IllegalArgumentException, NullPointerException, IndexOutOfBoundsException... Při výjimce může program skončit, pokusit se z výjimky zotavit, poslat ji volající funkci, vyhodit jinou výjimku (třeba více obecnou). **Ošetření výjimky**: try { //hlidany blok } catch (TypVyjimkyException promennaVyjimky) { //osetreni vyjimky } catch (ObecnejsiTypVyjimkyException promennaVyjimky) { //osetreni vyjimky. specialnejsi predchazi obecnejsi } finally { //v C++ finally neni //blok provedeny at je vyjimka vyhozena nebo ne //typicky zavreni otevreneho souboru, ukonceni sitoveho spojeni... //vyse zminene by klidne mohlo byt realizovano i v catchi, ale //finally slouzi spise k osetreni predcasneho ukonceni behu (return;) v try bloku } **Propagace výjimky**: k ošetření dojde o jednu nebo více úrovní výše public class Evil{ public static void main(String[] args) { try { DoEvilWithFive(); } catch(Exception e) { //zachytí obecnou vyjímku System.out.println("You are such an evil man."); } } public void DoEvilWithFive() throws DivideByZeroException{ this.doEvil(5); //vyhodí vyjímku která je vypropagována do main } public void doEvil(int number) throws DivideByZeroException{ int evil; evil = number/0; //vyhodí vyjímku dělení nulou, která je vypropagována do metody DoEvilWithFive() } } ===== Událostmi řízené programování ===== Základní princip reakce objektového programu na vnější akci. Používá se např. u programů s GUI -- běh programu je řízen událostmi. Objekty GUI mají nadefinovány události (eventy; např. onClick, onMouseOut, onLoad, onClose...) a programátor k nim programuje metody -- eventListenery -- obsahující příkazy (např. volání privátních metod) které na událost reagují. Události však nejsou pouze u objektů GUI, používají se u veškerých objektů, kde může vzniknout událost (object.onUnload, timer.onTimeout, http.onResponse, thread.onDispose...). Událostmi řízené programování bývá vícevláknové, ale většinou spouštění vláken řídí běhové prostředí a my se o vlákna starat nemusíme. Existují ale případy, kdy je vhodné si separátní vlákna spustit samostatně (např. z důvodu využití výkonu vícejádrových procesorů). //kód je v C# public class GUI: Form { private Button tlacitko; private void GUI(){ this.tlacitko = new Button(); this.tlacitko.Text = "Spusť poplach"; this.tlacitko.Click += new System.EventHandler(this.tlacitko_Click_Handler); } private void tlacitko_Click_Handler(object sender, EventArgs e){ MessageBox.Show("Poplach, poplach, poplach"); } } ===== Několik rozdílů mezi C++ a Javou a C# ===== Každý z těchto jazyků vzniknul za jiným účelem - C++ jako objektová verze nízkoúrovňového jazyka C, Java jako abstrahovaná od platformy pomocí Java Virtual Machine. Několik důležitých rozdílů mezi těmito jazyky: **C++**: * Přímý přístup k zařízením (vhodné např. pro systémové programování) * Práce s datovými typy bez znaménka (unsigned long...) * Parametry předávány hodnotou, ukazatele odkazem * Manuální správa paměti (malloc, dealloc, free), garbage collector pomocí knihoven **Java** * Programování pro virtuální platformu - JVM * Nemá podporu pro unsigned typy * Automatická garbage collection * Just-in-time kompilace, bytekód **C#** * "Java" od Microsoftu - stejné principy (platforma .NET jen pro MS OS, implementace pro jiné platformy -- projekt Mono), velice podobné příkazy a vlastnosti * Kvalitní propojení s MS produkty (MS SQL Server, Exchange server, SharePoint, Office atd.) * Properties objektu (nahrazuji objekt.getVariableName(), objekt.setVariableName(value) metody). Př.: //kód je v C# public class test { private string attribute = null; //nastavovani vnitrni hodnoty attribute (get a set muzou obsahovat libovony kod) public string ManualProperty { get { return attribute; } set { attribute = value; } } //vyse uvedeny kod bez pouziti vnitrni promenne public string AutomaticProperty { get; set; } } * Automatická garbage collection ===== Seznam předmětů ===== [[https://is.muni.cz/auth/predmety/predmet.pl?fakulta=1433;id=455039;zpet=..%2Fpredmety%2Fkatalog.pl%3Ffakulta%3D1433%3Bhledret%3DC%2520OR%2520Java%3Bhledv%3Dnaz%3Bhledv%3Dkod%3Bfak%3D1433%3Buhledat%3D1;zpet_text=Zp%C4%9Bt%20na%20v%C3%BDb%C4%9Br%20p%C5%99edm%C4%9Bt%C5%AF|PB161: Programování v jazyce C++]] [[https://is.muni.cz/auth/predmety/predmet.pl?fakulta=1433;id=455040;zpet=..%2Fpredmety%2Fkatalog.pl%3Ffakulta%3D1433%3Bhledret%3DC%2520OR%2520Java%3Bhledv%3Dnaz%3Bhledv%3Dkod%3Bfak%3D1433%3Buhledat%3D1;zpet_text=Zp%C4%9Bt%20na%20v%C3%BDb%C4%9Br%20p%C5%99edm%C4%9Bt%C5%AF|PB162: Programování v jazyce Java]] [[http://www.fi.muni.cz/usr/jkucera/pb161/ |Stránky k předmětu PB161]] [[http://is.muni.cz/dok/rfmgr.pl?fakulta=1433;obdobi=3724;kod=PB162;furl=%2Fel%2F1433%2Fpodzim2007%2FPB162%2Fum%2F;info= | Stránky k předmětu PB162]] ===== Použitá literatura ===== [[http://cs.wikipedia.org/wiki/Objektově_orientované_programování| OOP (Wiki CS)]] [[http://kore.fi.muni.cz:5080/wiki/index.php/Java:Objektový_návrh_v_Javě|Objektový návrh v Javě (FI Wiki)]] [[http://skola.isd.cz/java/13_vyjimky.pdf|Výjimky (PDF)]] [[http://www.fi.muni.cz/~tomp/slides/pb162/foilgrp14.html|Událostmi řízené programování]] ===== Vypracuje ===== Kuba Talaš (icq 257208851) Vesměs hotovo, případně se vyjádřete v diskuzi nebo přímo upravte wikistránku. Iniciativě se meze nekladou ;) ~~DISCUSSION~~