650 likes | 857 Views
Programování 02. OOP. Vývoj programovacích technik. Strukturované programování Modulární programování Objektově orientované programování S tímto vývojem je spojeno: zvyšování úrovně abstrakce posilování principu ukrývání dat a implementačních detailů
E N D
Programování 02 OOP
Vývoj programovacích technik • Strukturované programování • Modulární programování • Objektově orientované programování S tímto vývojem je spojeno: • zvyšování úrovně abstrakce • posilování principu ukrývání dat a implementačních detailů Cílem těchto technik je zefektivnit tvorbu programů a zajistit, že vytvořené programy budou mít jasnou a srozumitelnou strukturu a budou snadno ověřitelné a rozšiřitelné.
Paradigmataprogramování side effects, údržba nelze rozumně rozšiřovat dále – generické programování šablony, STL Procedurálníprogramování • jakouakcimámprovést • vstup – výpočet (algoritmus) – výstup • black box:procedura / funkce Modulárníprogramování • rozděleníproblémunakomponenty • procedurypracujínaddaty - rozhraní • black box:modul Datováabstrakce • vytvořenívlastníhodatovéhotypu(abstract/user defined datovétypy) • kompletnímnožinaoperacínadtímtotypem • black box:datovýtyp Objektovéprogramování • dědičnost – obecné / konkrétnívlastnosti • Polymorfismus – odlišné chování potomků • možnostpozdějšíchrozšíření • zapouzdření
Strukturované programování Zásady a postupy strukturovaného programování: • postup shora dolů při tvorbě programu • používání doporučených datových a příkazových struktur • nepoužívání (resp. minimalizace používání) příkazu goto • členění programu do podprogramů • grafická úprava programu, zvýrazňující jeho strukturu • používání výstižných identifikátorů a účelných komentářů
Příkaz goto v Pascalu Příkaz goto (příkaz skoku) způsobí předání řízení na příkaz označený návěštím. ... gotonávěští; ... návěští: příkaz; ... Návěští je identifikátor nebo celé číslo bez znaménka od 0 do 9999 a musí být deklarováno v nejblíže nadřazeném bloku deklarací labelnávěští; Příkaz skoku i označený příkaz se musejí nacházet v témž bloku. To znamená, že nejsou možné skoky dovnitř bloku nebo ven z bloku. Označený příkaz může být prázdný a tudíž je možné návěštím označit také koncové end nějaké příkazové struktury.
Modulární programování Modulární programování spočívá v členění programu do programových modulů (jednotek), které jsou samostatně kompilovatelné. program moduly procedury a funkce . . . . . .
Struktura modulu • Jméno modulu • Rozhraní (interface) modulu • dovoz modulu • vývoz modulu • deklarace veřejných konstant, proměnných a typů • specifikace veřejných operací (procedur a funkcí) • Implementační část modulu • deklarace soukromých konstant, proměnných a typů • specifikace a implementace soukromých operací • implementace veřejných operací
Objektově orientované programování Objektově orientované programování je přístup k tvorbě programů, založený na využití objektů a jejich vlastností. Zahrnuje analýzu problému, návrh struktury programu i způsob psaní programu. Základní pojmy: objekt, třída (objektový typ), posílání zpráv, zapouzdření, dědičnost, polymorfismus.
Objekt Objekt je programová struktura, obsahující jak data, tak metody, které s těmito daty pracují. Zapouzdření(encapsulation) znamená, že data objektu jsou přístupná pouze prostřednictvím metod tohoto objektu. metody data
Třída (class) Třídaje skupina objektů, které mají stejné vlastnosti (atributy, datové složky) a stejné chování (metody). Objekt, který patří do určité třídy, se nazývá instance této třídy. Atributy (datové složky): • atributy třídy • atributy instancí Metody: • metody třídy (např. konstruktor) • metody instancí (např. destruktor)
Dědičnost (inheritance) Od jedné třídy (bázové, rodičovské) můžeme odvodit třídu jinou (odvozenou, dceřinnou). Dceřinná třída (potomek) dědí všechny složky své rodičovské třídy (předka) a k nim může přidat svoje vlastní. Zděděné metody je možno předefinovat. Potomek může v programu vždy zastoupit předka (i nepřímého). Naopak to možné není. Dědičnost může být: • jednoduchá (třída má jednoho rodiče) • vícenásobná (třída má více rodičů)
Třídy, objekty a dědičnost M1 Třída T A1, A2 vytvoření instance Atributy: A1, A2 M2 Metody: M1, M2 odvození třídy M1 M3 Třída T1 (od T) A1, A2, A3 Atributy: A3 Metody: M1, M3 M2
Koncepční pohled objekt: entita reagující na vnější podněty třída: množina stejně reagujících entit Technický pohled objekt: struktura obsahující data a funkce, instance třídy (proměnná) třída: typ objektu – jednotná struktura dat, stejné operace nad daty Zobecnění pojmu struktura (struct) Rozdíl mezi class a struct v C++ je nepatrný, užívání class je pouze konvence deklarace třídy obsahuje Deklarace datových položek (stejně jako v C) Funkce (metody), virtuální funkce a statické funkce Definice výčtových konstant a typů (včetně vnořených tříd) Rozhraní – veřejné informace a služby pro uživatele Implementace – (neveřejná) interní data a metody (funkce) Třídy a objekty
Skládání tříd a objektů m1 Třída T1 vytvoření instance a1, a2 Atributy: a1, a2 m3 m2 Metody: m1,m2,m3 M1 m1 Třída T2 a1, a2 Atributy: A typu T1 m3 m2 Metody: M1, M2 M2
Posílání zpráv Objekty spolu komunikují tak, že si navzájem posílají zprávy. Obvykle to znamená, že jeden objekt (odesilatel zprávy) volá metodu jiného objektu (příjemce zprávy). Časná vazba(early binding): Příjemce zprávy je určen v okamžiku kompilace. Pozdní vazba (late binding): Příjemce zprávy je určen až za běhu programu. Pomocí pozdní vazby se realizuje polymorfismus(mnohotvarost). To znamená, že určitá metoda se může v různých kontextech chovat různě.
Třída zvíře v PHP definice třídy class Zvire { private: $zaludek=0; function __construct() { $zaludek = 1; }; public function zije() { return $zaludek>0; }; public function jez($jidlo){if( ! zije()) return 0; return zaludek += jidlo;} public function vymesuj($ objem){ if( (zaludek -= objem) <= 0) zaludek = 0; return zaludek;} }; zvire.php rozhraní (veřejné) vnitřní stav (privátní) Datová položka konstruktor (inicializace) inline tělo funkce metody Deklarace metody
Třída zvíře - použití class Zvire { private: int zaludek; public: Zvire() { ... }; int zije() { ... }; int jez( int jidlo); int vymesuj( int objem); }; include ”zvire.php” ..... { ..... $pytlik= new Zvire; pytlik->jez(5); pytlik->vymesuj(3); if( ! Pytlik->zije()) return -1; pytlik->vymesuj(4); if( ! Pytlik->jez(1)) return -2; ..... } -1 0 mujprogram.cpp zvire.php Import rozhraní Automatický konstruktor zaludek = 1 Instance třídy = objekt zaludek = 6 zaludek = 3
Objekt - instance třídy Public function jez($jidlo) { if( ! this->zije()) return 0; return $zaludek += $jidlo; } ..... $pytlik=new Zvire;$beruska=new Zvire; pytlik->jez( 5); beruska->jez( 1); ..... zaludek 6 zaludek 2 dvě instance třídy Metoda třídy - ke kterému objektu má přistupovat? ? pytlik: beruska:
Přetěžování funkcí Funkce je definována svým identifikátorem a počtem a typem parametrů function pocitej($x) { return $x+1; } Function pocitej($a, $b) { return 2*$a + $b; } Function pocitej($a, $s) { return $a + strlen( $s); } pocitej( 1); // pocitej($x) pocitej( 1, 2); // pocitej($a, $b) pocitej( 1, "ahoj"); // pocitej($a, $s) Funkce se stejným identifikátorem ale různým počtem parametrů Funkce se stejným počtem ale různým typem parametrů Správná funkce podle počtu a typů skutečných parametrů
Implicitní parametry Některé parametry funkce mohou mít implicitní hodnoty • pokud nejsou všechny parametry implicitní – implicitní parametry odzadu Při volání funkce lze implicitní parametry vynechat • použije se implicitní hodnota Kdy použít přetěžování a kdy implicitní parametry? • Stejný kód pro různý počet parametrů implicitní parametry • Pro různé počty nebo typy parametrů různý kód přetěžování Function fce( $a, $b = 2, $c = 4) { return 2*$a + $b - $c; } fce( 1); // fce( 1, 2, 4) fce( 1, 5); // fce( 1, 5, 4) fce( 1, 5, 6); // fce( 1, 5, 6) Volá se stále stejná funkce int fce( int, int, int)
Konstruktory class Zvire { private: $zaludek=0; public: function __construct() { zaludek = 1; }; function __construct($zal) { $this->zaludek = $zal; }; }; $Beruska=new Zvire; $pytlik= new Zvire( 20); $beberuska=new Zvire( beruska); různé zápisy copy konstruktoru Implicitní konstruktor bez parametrů Konstruktor s parametry Copy konstruktor X (const X&) vytvoří objekt jako kopii jiného
class Bod { public: Bod( const Bod& b) { dosad(b); }; Bod operator=( const Bod& b) { dosad(b); return *this; }; int GetX() {return x; }; int GetY() {return y; }; void SetX(int x) { this->x = x; } void SetY(int y) { this->y = y; } private: int x, y; void dosad( const Bod & b) { x=b.x; y=b.y; }; }; Udržovatelnost kódu • Těla operátorů a konstruktorů • volání jiné funkce • Public část před private • Private položky nejsou zajímavé • Datové položky vždy private • Funkce Get a Set • Těla metod vždy v *.cpp souboru • Pro pozdější rozšíření • Lépe se hledá kde je implementované • Jména tříd • ToJeMojeTrida • Jména funkcí proměnných • mojePrvniFunkce
Třída se přestavuje • ClassCucitel{ • Var $vyska, $vaha, $jmeno; • Function __construct ($vyska, $vaha, $jmeno) { • $this->vyska=$ vyska; • $this->vaha= $vaha; • $this->jmeno = $jmeno; • $this->ServatStudenty(); • } • Function __destruct () { • Unset($this->vyska); • Unset($this->$vaha); • Unset($this->$prinost); • […] • } • FunctionServatStudenty() • Echo „Tady bude ticho!!!“ • } • } • Třída • Vlastnosti • Konstruktor • Naplnění • Zavolání metody • Destruktor • Metoda
Třídy a objekty • Class scope vlastnosti: použitím operátoru „::“ • (PHP4) bohužel žádné class-scope atributy • (PHP5) lze vytvořit konstanty define()d • class Person { • function id() { return "Person"; } • const species = "Homo Sapiens"; • } • echo Person::id()."is".Person::species;
Porovnání objektů • rovnost kontroluje strukturu objektu a třídy • shodnost kontroluje samotný objekt • $a = new Person(); • $b = new Child("whale"); • $c =& $a; • ($a == $b) ? "equal" : "neq"; • ($a === $c) ? "identical" : "non-id";
PHP5: přidané vlastnosti • Abstraktní třídy, rozhraní • stejné jako v Javě • abstraktní třída má nejméně jednu abstraktní metodu • rozhraní definuje pouze hlavičky metod • Vzorové nápovědy v funkcích • urychluje psaní formálních parametrů • public function test(OtherClass $othercalss) … • fatal error on type mismatch • Objektové iterace • foreach iteruje přes všechny viditelné atributy • můžene redefinovat přes rozhraní Iterator • rewind(), current(), next(), key(), valid() metody
PHP5: přidané vlastnosti (2) • Magické metody • začínající __ prefixem (vyhrazeno) • __sleep(), __wakeup() pro serializaci • __toString() pro přímé použití echo $object • __clone() pro hluboké kopie bez kopírování referencí • Výjimky • try-catch bloky (ne finally) • throw objekt Exception nebo potomka • neobsloužená výjimka => fatal error • globálně lze set_exception_handler($function)
Nelze vše vidět… • Třída • Public - přístupná všem uživatelům třídy. • Protected - přístupná uživatelům třídy (rodiče) a podtřídy, která tuto třídu dědí. • Private - přístupná pouze uvnitř třídy. • Vytvoření objektu • Voláme metodu objektu • Přístupujeme k vlastnosti ClassCucitel{ […] public $verejna = 'Veřejná'; protected $chranena = 'Chráněná'; private $soukroma = 'Soukromá'; } $Skop = newCucitel (185, NaN, „Škop“); $Skop->servatStudenty(); Echo $Skop->jmeno;
Učitel zplodí potomka • ClassCmucitelextendsCucitel{ • Var $hlasitost=1; • Function __construct ($vyska, $vaha, $jmeno, $hlasitost) { • $this->vyska=$ vyska; • $this->vaha= $vaha; • $this->jmeno = $jmeno; • $this->hlasitost=$hlasitost • $this->servatStudenty(); • } • FunctionservatStudenty($hlasitost) • for ($i=0;$i<$hlasitost;$i++) • Echo „Tady bude ticho!!!“ • } • } • $LM= newCmucitel (182, 80, „LM“,5) ; • $LM::servatStudenty(); //funguje jen unitřCmucitel • Třída • Nová vlastnost • Nový konstruktor • Přepisujeme metodu • Vytváříme objekt • Voláme překrytou metodu
Objektové rozhraní - interface • Vytvoříte kostru třídy a výsledná třída poté kostru jen implementuje. interface Rozhrani{ public functionVypisuRozhrani(); public functionVypisParametr($parametr); } classTridaimplementsRozhrani{ public functionVypisuRozhrani(){ echo 'Rozhraní bylo zahrnuto'; } public functionVypisParametr($parametr){ echo $parametr; } } $tr = newTrida; $tr->VypisuRozhrani(); $tr->VypisParametr('Vypíše paramtr'); Definice rozhraní Musí být public Třída, která implementuje rozhraní
Operátory new a delete new: alokace paměti, zavolání konstruktoru • není nutno testovat úspěšnost – mechanismus výjimek delete: v PHP neexistuje příkaz delete, destruktor se volá v případě skriptu pomocí funkce exit(). Pro dealokaci paměti proměnných se používá unset $pb = newBod( $a); $pc = newBod( 3, 5); $a = $pb + $pc; Volání třídy
Destruktory ukazatel na alokovaná data class Str { private: $buf=„“; public: function __construct () { $this->buf = 0; }; function __destruct() { unset($this->buf); }; }; alokace paměti pro řetězec destruktor - automaticky se volá při zrušení objektu
vztah tříd předek-potomek – hierarchie přesnější názvosloví: základní (base) / odvozená třída (derived class) vícenásobná dědičnost dvakrát měř, jednou řež, protokoly specializace potomek má/umí něco navíc reusabilita jiné chování bez změny původní třídy Dědičnost Zvíře Pes Pitbul Člověk jez, vyměšuj sedni, lehni trhej uč_se
pes jako potomek zvířete - definice class Zvire { protected: $zaludek=0; public: function __construct(); function __construct($jidlo); function zije(); function jez($jidlo); function vymesuj($objem); }; potomek (odvozená třída od) Zvířete class Pes extendsZvire { private: $stav=0;//0-Stoji, 1-Sedi, 2-Lezi public: function __construct() { $this->stav = 1; }; public function sedni() { $stav = 1; }; public function codela() { return $stav; } }; přidaná položka položky předka metody předka $pytlik=new Zvire(); $azor=new Pes(); Pytlik->jez(); Azor->jez(); Azor->sedni(); stav žaludek položky potomka metody potomka potomek obsahuje všechny položky a metody předka Přístup pro třídu a potomky jez, vyměšuj sedni
Konstruktor a destruktor předka implicitní konstruktor předka (automaticky) class Zvire { ... function __destructor () { echo "zabijim zvire "; } }; class Pes extends Zvire { ... public: function __construct() { $this->stav = 0; /*Stoji*/ } function __construct($jidlo){$this->stav = 0;/*Stoji*/} function __destruct() { echo "zabijim psa "; } }; { $azor=new Pes; ... } explicitní konstruktor předka konstruktory předků a vložených tříd se volají před konstruktorem potomka destruktor předka se vyvolá automaticky po ukončení destruktoru potomka zabijim psa zabijim zvire
Potomka lze přiřadit do předka Předka NELZE přiřadit do potomka Kompatibilita předka a potomka pes umí jíst, brouk neumí štěkat $pytlik=newZvire; $azor=new Pes; pytlik = azor; stav žaludek žaludek stav azor = pytlik; žaludek žaludek nelze azor pytlik azor pytlik ???
odlišné chování potomků – pozdní vazba (late binding) Polymorfismus Zvíře Pes Pitbul sní maso sní hodně masa najde něco v přírodě Člověk jde do restaurace jez jez jez jez
Polymorfismus - motivace Tohle není polymorfismus ! class Zvire { public function jez() { priroda(); }; }; class Pes extends Zvire { public function jez() { maso(1); }; }; class Pitbul extends public Pes { public function jez() { maso(10); }; }; class Clovek extends Zvire { public function jez() { hospoda(); }; }; $pytlik=new Zvire; $punta=new Pes; $zorro=new Pitbul; $pepa=new Clovek; Pytlik->jez(); // priroda(); Punta->jez(); // maso(1); Zorro->jez(); // maso(10); Pepa->jez(); // hospoda(); 'normální' vlastnost tříd zakrývání metod Při překladu je známo ze které třídy se volá metoda Každá třída má vlastní implementaci (tělo) metody jez
Nesprávné užití dědičnosti Letadlo není potomkem svého motoru Důkaz: Co když má dva motory... Násobná dědičnost? Ne: Je třeba je odlišit Jezevčík umí vyhnat lišku z nory... Myslivec s jezevčíkem tedy také... Myslivec není potomkem svého jezevčíka Důkaz: Nežere granule... Kompozice? Ne: Nerodí se zároveň Mlok není potomkem ryby a savce Důkaz: Nemá dvě hlavy... Virtuální dědičnost? Ne: Nekojí Tlačítko není potomkem obdélníku a textu Kompozice • Skládání velkých objektů z malých Delegace • Převedení funkčnosti na jiný objekt Společný abstraktní předek • Obratlovec
Prostory jmen (namespaces) definice prostoru jmen zapouzdření identifikátorů prevence kolizí (velké projekty, knihovny) stejné identifikátory v různých prostorech jmen namespace aa { $p=0; function f1($x) { return $x + $p; } function f2($x, $y); } aa::f2($x, $y) { return $p * ($x + $y); } aa::f1( aa::f2( 5, 6)); přístup k identifikátoru ze stejného prostoru definice funkce mimo prostor jmen přístup k identifikátorům přes ::
Prostory jmen prostor jmen se může opakovaně otevírat a zavírat explicitní přístup ke globálnímu identifikátoru ::id standardní knihovny – namespace std rozbalení std using namespace std; namespace aa { $p=0; $q=0; } Function g($n) { cout << ($n + aa::$p); } namespace aa { function f3($x) { return 1 + ::g($x); } přístup do aa přístup k identifikátorům std znovuotevření prostoru aa přístup ke globálnímu identifikátoru
Konstanty • neměnné proměnné se stringovými jmény • používá konstrukci define() • žádný $ příznak • define("COUNT", 80); • ... if (!defined("COUNT") die("No count."); for ($i=0; $i<COUNT; ++i) echo $i; • – pouze skalární typy (žádné pole, objekty)
Rozsah proměnných • globální proměnné: deklarovány na nejvyšší úrovni • lokální proměnné: deklarovány uvnitř funkcí • statické proměnné – jako v C • konflikty jmen řešeny pomocí global • superglobals – speciální globální pole • nepotřebují deklarovat jako globální uvnitř funkcí • asociativní pole s proměnnými HTTP atd. • $_GET[], $_POST, $_COOKIE, $_SERVER • $_FILES, $_SESSION, $_ENV, $GLOBALS
Vkládání souborů • require() • require("/inc/main.php"); • vloží obsah souboru/URL nebo error • include() include("_head.php"); • vloží obsah souboru/URL nebo varování • pozor • soubory musí být samostatné PHP • žádné funkce => if () { include($file) } • do verze 4.0.2, require() čte i v případech jako if(false) • require(„file.inc“) • neopakovaná inkluze: konstruktor *_once()
Funkce pro práci s poli • array_merge — Sloučit dvě nebo více polí • array_push — Přidat jeden nebo více prvků na konec pole • array_rand — Vybrat náhodně jeden nebo více prvků pole • array_reverse — Vrátit pole s prvky v opačném pořadí • array_shift — Odstranit prvek ze začátku pole • array_splice — Odstranit část pole a nahradit ji něčím jiným • array_unique — Odstranit z pole duplicitní hodnoty • array_values — Vrátit všechny hodnoty v poli • array — Vytvořit pole • end — Nastavit vnitřní ukazatel pole na jeho poslední prvek • foreach – Posunout interní ukazatel pole • pos — Získat současný prvek pole • reset — Nastavit interní ukazatel pole na jeho první prvek • rsort — Třídit pole sestupně • shuffle — Zamíchat pole • sizeof — Zjistit počet prvků v poli • sort — Třídit pole
Výjimky Motivace: co dělat, když (knihovní) funkce zjistí chybu? nedostatek paměti, nelze otevřít soubor, nulový ukazatel, ... • Vypsat zprávu na 'obrazovku' a skončit • FUJ! Nikdy! • Nastavit do globální funkce příznak chyby • problém s více vlákny, nutnost neustále testovat • Vrátit 'divnou' hodnotu • takhle funguje většina knihovních funkcí C • nepříliš praktické, testování každé funkce, vnořené testy • divná hodnota nemusí existovat Co chceme: • oddělit detekci výjimečné situace od jejího zpracování • po výskytu 'chyby' (výjimečné situace) automaticky skočit na zpracování • kulturně po sobě uklidit (volání destruktorů)
Výjimky - pravidla • k try bloku může být několik handlerů s různými typy • try bloky mohou být vnořené • výjimka může být vyvolána v libovolně zanořené funkci • po vyvolání výjimky se řízení předá handleru s odpovídajícím typem • před odchodem ze všech bloků se zavolají destruktory lokálních objektů • předávaná hodnota nese informaci o výjimce • typické použití: potomek standardní třídy exception • i pro výjimky platí, že potomek může nahradit předka • konstruktor runtime_error(string&), metoda string what() • po ošetření výjimky pokračuje program za handlery try bloku • při běhu bez výjimky se handlery ignorují (přeskočí) • neošetřená výjimka – unhandled exception, konec programu
Vztahy mezi objekty • Skládání • Delegace • Dědění
SKLÁDÁNÍ • Objekt obsahuje jiné objekty • Tyto tvoří jeho nedílnou část (bez nich nemůže být) • Obvykle vytvářeny při vytváření objektu kterému patří • Obvykle se nedostanou vně objekt
Delegace • Objekt využívá pro realizaci některých úloh služeb jiných objektů • Tyto objekty většinou pochází z venku (je předán odkaz na ně) • Využívané objekty netvoří logickou součást