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

  1. 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)
  2. překrytí(override) - objekt přetěžuje(znovu definuje) poděděnou metodu (2)
  3. 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 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ů

Použitá literatura

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 ;)

Diskuze

, 2008/05/29 11:02

Co takhle dopsat neco malo o podotazce objektove programovani v imperativnim jazyce? Nebo kde to tady mam hledat? Jak jsem jiz psal na foru v ISu Javu jsem bohuzel nemel a v C++ se o tom zas tolik nemluvilo jak jiz psal kolega Filip Nespor. Proto navrhuji autorovi, aby pridal podnadpis OOP v imperativnim jazyce a neco o tom malo napsal, aby kdyz si to nahodou nekdo vytahne a oni se ho na tohle zeptaly u komise(protoze na papire o tom nic mit nebude), aby jim o tom neco dokazal rict.Kolega psal na foru ze jsou rozdili v (konstruktorech objektu, typech objektu, vytvoreni objektu, dedicnosti objektu, garbage collectoru).
Diky za doplneni

, 2008/05/30 16:56

Jak to myslis? cela tahle otazka je o objektovem programovani. Nechapu presne co ti chybi. Nebo snad je problem v tom slovicku imperativni?

, 2008/06/01 20:22

Myslím že podotázka „oo v imperativním jazyce“ prostupuje celou touto stránkou.
Pěkná stránka rozdílů mezi Javou a C++ je http://en.wikipedia.org/wiki/Comparison_of_Java_and_C%2B%2B, její výtah do tohoto textu ještě zapracuju co nejdřív.

, 2008/06/02 13:00

Jj neco takoveho mam na mysli. Je me jasny ze je tahle otazka o OOP, ale podotazka teto otazky je OOP v imperativnim jazyce(toto chapu jako rict rozdil mezi OOP v obektovem jazyce a imperativnim jazyce). Jelikoz jsem Javu nemel, nejak me tato otazka zazkocila a proto zde zadam o pomoc nekoho, kdo se v tom lepe vyzna a Jakub muj dotaz pochopil, a tak to jsem prida a za te Dekuji

, 2008/06/02 14:23

Stejne si myslim ze pletes hrusky z jabkama. Neni zadny „objektovy jazyk“. Objektove orientovane programovani je technika ktera se vyskytuje prevazne v imperativnich jazycich (jednoduse receno ty ktere nejsou funkcionalni). C++ i java jsou imperativni jazyky s podporou OOP. Stare C nema tuto podporu ⇒ nemuzes tam programovat objektove.

Tou podotazkou se mysli priklady k tematu v jakemkoli imperativnim jazyce.


, 2008/06/02 16:06

No jasny ze neni „objektovy jazyk“ to melo bejt napsany v uvozovkach. Ja sem tu podotazku pochopil tak, ze to je proste vysvetlit rozdil mezi OOP v Jave(imperativni jazyk-objektove orientovany) a programovanim(neobjektovem)v strukturovanem jazyce(coz je tez imperativni jazyk, napr.C),jakoze v cem je OOP lepsi nez strukturovane, ale kdyz tak o tom premyslim, tak jsem mozna delal z komara velblouda, protoze jak jsi psal, tak tou podotazkou se mysli asi priklady. Ale co kdyz ne?

, 2008/06/08 22:46

Kdyz ne, tak tu mas otazku prevazne o strukturovanym imperativnim programovani jako takovym tak to snad zvladnes porovnat… naucit se o musis stejne oboje

, 2009/05/29 14:37

> Neni zadny „objektovy jazyk“.

A co SmallTalk? (:

, 2008/06/03 23:30

otazka byla odeslana na kontrolu, snad budem brzy vedet vic, jak to tedy ma byt :)

, 2008/06/04 09:37

Ad polymorfismus) nemělo by to být jinak? V PB006 jsme se učili o dvou typech: inkluzní a parametrický. Ten inkluzní je právě používán v imperativních jazycích, pokud vím, a je založenej na hierarchii tříd - typy a podtypy. Snad nekecám úplný nesmysly :-)

, 2008/06/07 14:53

Zkusím si najít čas a ještě po tomhletom zapátrat. Ty umíš člověka znejistět :-)

, 2008/06/08 16:32

Co tak pozret do materialom k predmetu Principy programovacich jazykov, myslim ze tam bol polymorfizmus vysvetleny dostatocne

, 2008/06/08 19:23

nekecas, vecer to tam dopisu, mas samo pravdu

, 2008/06/18 20:50

Nechci prudit, ale parametrický polymorfismus != přetížení. To, o čem se zmiňuje v textu, je jen přetížení. Radši tu zmínku o polymorfismu smažu.

, 2008/06/19 09:10

Klidně pruď, když svoje tvrzení podložíš literaturou, nebo věrohodným zdrojem tak to můžeš odmazat :), já našel v několika zdrojích, že to parametrický polymorfismus je(což ovšem nevylučuje, že byly špatně).

, 2008/06/19 09:38

Tak jo :-) skripta z PB006, stranou 46 počínaje: „Typ je parametricky polymorfní, zastupuje-li celou množinu monomorfních typů. Tato množina je generována náhradou typových proměnných všemi monomorfními typy. Parametrcky polymorfní typ je vyjádřen typovým výrazem se základními typy…“..dále…„otypování v parametricky polymorfních systémech je založeno na unifikaci typových výrazů, pro složitější systémy nerozhodnutelné“

Mně to nesedí na přetížení :-)

, 2008/06/20 15:21

Mě to na přetížení sedí - když metodu přetížíš na všechny základní typy co má jazyk, ve kterým programuješ, tak máš parametrickej polymorfismus, přesně jak jsem psal s tím zásobníkem, je úplně jedno co si do něj uložíš(int, string, klidně i object…). Jediné co musíme zmínit je to, že nejde o overload ve smyslu počtu parametrů. :-P
Pokud stále nesouhlasíš, tak mi prosím ukaž příklad, jak parametrický polymorfismus vypadá, ať můžu klidně spát :)

, 2009/06/21 03:53

parametrický polymorfismus a přetížení skutečně není to stejné.

u polymorfismu má např. jedna funkce nějaký obecný typ, který implicitně
zastupuje celou množinu všech možných myslitelných i nemyslitelných
odvoditelných (pod)typů
např. IsEmpty: List → Bool
Bool IsEmpty(List list) { return list[0] == null }
IsEmpty je potom zároveň typu IntList → Bool, FloatList → Bool, StringList →
Bool, …

kdežto u přetížení je několik funkcí se stejným jménem, ovšem různých
(explicitně uvedených) typů a různých implementací
např. Default: Void → Int, Default: Void → Float, Default: Void → String
Int Default() { return 0 }
Float Default() { return 0.0f }
String Default() { return ““ }

, 2008/06/22 23:12

v textu je “ Objekt také obsahuje“ neukoncene… nechybi tam neco?

mam trochu zmatek v pojmu „objekt“ a „instance“… zde https://is.muni.cz/auth/el/1433/podzim2006/PB162/um/02/printable.pdf se o objektu mluvi (dal v textu, str. 4) jako o instanci tridy, tedy objekt a instance je totez?

, 2009/06/10 23:28

Objekt je instanci triedy, ak sem náhodou ešte niekto príjde, komu to nebude úplne jasne :).

, 2009/06/20 20:09

Pisat podmienku ako if (allowNewName(newName) == true) … je podla mna zvrhlost… na co porovnavat boolean hodnotu na true alebo false? Staci if (allowNewName(newName)) …

Ja len tak, aby to niekto takto nenapisal ak od neho budu chciet nejaky priklad, to by sa podla mna komisia zasmiala :-)

, 2009/06/23 16:15

To rozhodně, odstranil jsem to.

, 2009/06/23 12:01

„OOP nedekomponuje problém shora dolů, ale zdola nahoru.“

s tím jsem u komise moc nepochodil, raději bych nezmiňoval :)

, 2010/06/19 23:54

Rozdělení výjimek na hlídané a nehlídané mi připadá nad rámec otázky. Navíc se týká jen Javy.

, 2011/06/16 19:24

Domnívám se, že problematika polymorfismu a přetížení je v textu špatně (nebo minimálně nepřesně):

Polymorfismus

* 'bezparametrický': Případ, kdy existuje mezi objekty dědičnost a jsou volány různé implementace „téže“ metody, podle aktuálního typu objektu.
* 'parametrický': Část programu nepracuje s klasickými datovými typy, ale s obecnými (generickými). Metoda tedy může přijmout například libovolný seznam List<T>, nehledě na datový typ T. Někdy může přijmout dokonce úplně libovolný datový typ.

Přetížení

V některých zdrojích je přetížení (overloading) od polymorfismu zcela oddělené, jinde uváděné jako ad-hoc polymorfismus.
* 'kontextově nezávislé': Jedno jméno funkce (metody) je použito pro více deklarací, každá z nich přijímá různý počet nebo typ parametrů.
* 'kontextově závislé': Podobně jako kontextově nezávislé, ale funkce může mít stejný počet i typ parametrů a liší se pouze návratovou hodnotou. V dnešních programovacích jazycích se s tímto už prakticky nesetkáme.
Klasickým příkladem přetížení může být operátor +, který dokáže pracovat s celými čísly, desetinnými a například v jazyce Java i s řetězci.

Zdroje:
http://en.wikipedia.org/wiki/Function_overloading
http://en.wikipedia.org/wiki/Polymorphism_%28computer_science%29
http://en.wikipedia.org/wiki/Ad-hoc_polymorphism
Liborkovy slajdy k principům (dostupné jako PDF na fimuny, PS na http://www.fi.muni.cz/usr/skarvada/vyuka/PB006/sl-1.ps )

You could leave a comment if you were logged in.
home/prog/ap4.txt · Poslední úprava: 2020/04/12 16:56 (upraveno mimo DokuWiki)
Nahoru
CC Attribution-Noncommercial-Share Alike 4.0 International
chimeric.de = chi`s home Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0