====== 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~~