| POPIS: Jaké jsou programovací techniky. |
Programovací techniky
• Zakázkový software
–Zadavatel má nápad a peníze, ale neumí to udělat najde si realizátora
–Např. ŠIS
–Podtyp: subdodávka komplexního řešení
• Hlavní dodavatel je vůči subdodovatelůmv roli zadavatele
• Software pro volný trh
–Firma vymyslí a vytvoří program, pak se ho snaží prodat (mnoha) zákazníkům
–Např. MS Windows, Adobe Photoshop, …
• Interní projekt
–Firma si pro své vnitřní potřeby vytvoří software (zadavatel a realizátor jsou různá oddělení stejné firmy)
• Jiné typy projektů
–Open source projekty (Linux, Firefox, …)
• Řada projektů je zvláštních: není zde jasný zadavatel (co má program dělat), část práce odvedou dobrovolníci
(zdarma) –často role zadavatele, realizátora i finančního zdroje hraje komunita
My se dále podrobněji podíváme na tvorbu zakázkového software (dobře se na tom ukazují jednotlivé činnosti)
• Tedy jaké činnosti zahrnuje tvorba software?
–(U zakázkového typu)
• Zadavatel musí sdělit, co vlastně chce
• Přenos myšlenky není nikdy dokonalý
–Nevyřčené předpoklady (na obou stranách)
–Špatné pochopení (na obou stranách)
–Neznalosti (na obou stranách)
–Střet dvou světů
• Člověk (vágní) a počítač (přesný)
–Co s tím?
• Komunikace musí být obousměrná (↔)
–Aktivně se ptát
• Proč to chcete? Co je cílem?
–Někdy je lepší úplně jiné řešení, než s kterým zadavatel původně přijde
–Vyjasňovat si, ověřovat si
• Nakreslit, ukázat (ukázkové verze co nejdříve –nemusí být plně funkční)
• Např. use cases(případy užití) –jak se program bude používat (scénáře užívání)
• Zápis dohodnutého formální specifikace
• Seznam kroků, jak v programu dosáhnout nějakého cíle
–Obvykle kroky popisující interakci mezi uživatelem a programem
• Např. přihlášení na zkoušku v ŠISu:
1. Student vybere akci „přihlášení na zkoušku“.
2. ŠIS vypíše seznam předmětů, které má student v daný semestr zapsané
3. Student vybere, o který předmět mu jde
4. ŠIS vypíše seznam zkouškových a zápočtových termínů daného předmětu (na které se v aktuální okamžik dá přihlásit, tj. jsme v časovém intervalu začátek přihlášení –konec přihlášení)
5. Student si vybere termín a kliknutím na „Přihlásit se“ se na něj přihlásí
6. ŠIS zobrazí potvrzení, že se přihlášení povedlo, a zobrazí seznam všech termínů, na které je student aktuálně přihlášen
• Zápis use cases:
–Různě (text i diagramy), často se využívá jazyk UML
• Oproti prostému seznamu funkcí programu mají use casesnapříklad tyto přínosy:
–Umožňují programátorům lépe pochopit, jak se dané funkce budou využívat (např. jaký je jejich kontext, jaké je pořadí), a tak vedou k lepšímu návrhu programu (návrh uživatelského rozhraní, volba vhodných datových struktur a algoritmů)
–Obvykle zachycují to nejdůležitější, co má program umět (tj. lépe se stanovují priority)
–Vedou k upřesňování ošidných situací („co má program dělat, když se stane to a to“) –a to už v rané části vývoje (specifikace, návrh, ne až v okamžiku implementace)
• Specifikace:
–Funkce programu
•Programátorské rozhraní (API), protokoly, …
–Uživatelské rozhraní programu
–Vlastnosti (rychlost)
–Platforma (HW i SW)
• Připravit se na změny programu
–Proč?
• Změna názoru, nový nápad, změnila se situace (na trhu, legislativa, v podniku, …)
–Počítat s tím v časovém plánu
–Návrh programu udělat (trochu) obecnější
• Aby změny byly snazší
• Kdepak, nejdříve musím vybrat…
–Vhodné nástroje, prostředky a lidi
• Platformu (není-li součástí zadání)
• Knihovny(frameworky, toolkity, grafický engine)
–Nemá smysl vše tvořit od nuly, je možné využít už hotová řešení
• Programovací jazyk
• Vývojové prostředí (IDE)
• Lidé (role a počet)
• Metoda vývoje / řízení projektu
• Kdepak, nejdříve musím udělat analýzu (rozbor) a poté udělat…
–Návrh (design)
• Celková architektura (moduly, objekty, co bude na serveru, co na klientovi, rozhraní, protokoly …)
• Algoritmy
• Datové struktury
• Uživatelské rozhraní
• Kdepak, nejdříve si celý projekt musím naplánovat…
–Čas (termíny)
–Finance
–Organizační (postup, priority)
–Právnízáležitosti (smlouvy, licence)
• Každý program obsahuje chyby testování, ověřování, kontrola kvality
–Funkční chyby
–Nemá požadované vlastnosti („je to ošklivé a pomalé“)
–Bezpečnostní chyby
• Funkce manažera*
–Plánování–stanovení cílů, určení variant, určení termínů
–Organizování–stanovení úkolů jednotlivým lidem a určování pravomocí, odpovědnost, organizační struktura
–Vedení–ovlivňování a motivování lidí, usměrňování a odměňování
–Rozhodování–také řízení rizik
–Kontrola–zjišťování odchylek, hledání příčin a způsobů nápravy
• Tím jsme shrnuli předchozích 5 snímků
• Ani náhodou:
–Dokumentace
• Uživatelská –aby uživatelé věděli, jak produkt nainstalovat a používat
• Programátorská –aby programátor věděl, kam „šáhnout“, když chce něco změnit, opravit nebo vylepšit
• Popř. projektová dokumentace (finance, čas, …) –aby podobné projekty proběhly stejně dobře nebo lépe
–Prodej, distribuce, propagace (u software pro volný trh)
–Nasazení software u zákazníka (deployment), integrace do jeho prostředí
–Podpora
• Uživatelská
–Aby uživatelé věděli, jak produkt a používat
–Popis instalace(systémové požadavky: HW a SW), představení funkcí programu, vysvětlení ovládání, …
• Programátorská
–Aby programátor věděl, kam „šáhnout“, když chce něco změnit, opravit nebo vylepšit
–Popis struktury programu, složitějších algoritmů, datových struktur, rozhraní, protokolů
• Zahrnuje i komentáře ve zdrojovém kódu
• Projektová
–Aby byl projekt dokončen a aby podobné projekty proběhly stejně dobře nebo lépe
–Co se kdy dohodlo (a popř. i důvody), jak dlouho daná věc trvala, kolik to stálo peněz,
• SLA(Service-LevelAgreement)
–Dohoda o úrovni poskytovaných služeb
• Hotline, Help desk, Call centrum
–Osobně/telefonicky/e-mail/webový formulář?
–Jen čtvrtek 10:00–16:00, nebo non-stop každý den?
• Školení uživatelů a správců systému
• Oprava chyb
–Jak rychlá reakce na nahlášenou chybu?
• Další rozvoj programu (nové funkce)
–Dohoda o tom:
• jaké služby, jaká úroveň, jak dlouho (30 dní, 1 rok, 5 let, …), za jakou cenu
1. Zadání (co má dělat)
2. Algoritmus(postup, jak to má dělat)
3. Zdrojový kód(text)
4. Strojový kód(01001001…)
• Postup řešení dané úlohy
• Například algoritmus sečtení dvou dlouhých celých čísel (487512493 + 9345678):
–Napiš čísla pod sebe (zarovnáno vpravo)
–Postupuj po číslicích zprava doleva:
• Sečti dvě číslice nad sebou
• Je-li výsledek 0 až 9, zapiš výsledek
• Je-li výsledek 10 a více, zapiš poslední číslici a 1 jde dále (do následujícího součtu)
• Pokud číslice chybí (číslo je krátké), domysli si tam 0
• Text, který:
–Napsán člověkem(většinou)
–Je v programovacím jazyce
–Popisuje chování programu
• Příslušný textový soubor má příponu obvykle podle použitého programovacího jazyka
–*.cpp(C++), *.cs(C#), *.java(Java), *.pas (Pascal), *.php(PHP), *.js(JavaScript), …
• Binární kód
–Generován (většinou)
–V jazyce stroje (počítače, hardware, procesoru)
• Rozumí mu procesor (CPU)
• Pro různé procesory může být strojový kód jiný
–Posloupnost příkazů (instrukcí) pro počítač
• Binární soubory se strojovým kódem mívají příponu podle zvyklostí daného OS:
–Windows: *.com, *.exe, *.dll
•exe= executable(spustitelný, proveditelný), jde o formát PE (Portable Executable)
–Linux: bez přípony (ale s právem „execute“)
• Jde o formát ELF (Executableand LinkableFormat)
• Zdrojový kód není na počítači (hardware) přímo spustitelný (proveditelný)
–Hardware (procesor) mu nerozumí
• Jak vykonat takový program?
–Interpretace
• Interpret provede ty kroky, které jsou ve zdrojovém kódu uvedeny
–Překlad(kompilace) do strojového kódu
• Překladač (compiler) převede (přeloží) program do podoby strojového kódu dané platformy (procesoru)
• Speciální program, tzv. interpret, vezme jako svůj vstup daný zdrojový kód (text) a provede příslušné akce (které jsou ve zdrojovém kódu uvedeny)
–Daný programovací jazyk se pak často označuje jako skriptovací jazyk(scriptinglanguage)
• PHP, Javascript, Python, batchfile(*.bat), shellscript(*.sh), …
–Interpret je ve formě strojového kódu (např. *.exe)
–Příklady interpretrů:
• JavaScriptengine(součást webových prohlížečů), cmd.exe (pro dávkové soubory *.batna Windows), Bash(pro tzv. shellskripty *.shna Linuxu), php.exe (PHP engine), …
• Převod z programovacího jazyka (tj. zdrojového kódu) do jazyka stroje (strojového kódu)
–Provádí speciální program: překladač(compiler)
• Musí umět oba jazyky
• Je ve formě strojového kódu (např. *.exe)
• Příklady:
–cl.exe (Microsoft VisualStudio), GCC (GNU CompilerCollection), Intel C++ Compiler(překladač od výrobce procesorů)
–Typické pro tyto jazyky:
• Pascal, C, C++
• Překlad nemusí být vždy až do strojového kódu nějakého procesoru (hardware)
• Překlad může být jen „na půl cesty“, do kódu nějakého pomyslného (virtuálního) procesoru
–Typické pro jazyky Java nebo C#
–Takový kód se označuje jako bajtkód(bytecode) nebo p-code(portable, přenositelný)
• Pro člověka je obvykle nečitelný (jde o binární kód)
• U C# se bajtkódukládá do souborů *.exe, u jazyka Java je to *.class
–Pro běh bajtkóduje nutný speciální program, který chod takového virtuálního procesoru (stroje) simuluje
• Např. Java Runtime Environment(JRE, běhové prostředí Java) nebo CommonLanguageRuntime (CLR, pro C#/.NET)
• Obsah *.exesouboru může být dvojí:
–Strojový kód (přímo spustitelný na procesoru)
–Bajtkód(pro spuštění je třeba CLR, což v praxi znamená mít nainstalován .NET Framework)
• U jazyka Java můžete narazit na dva typy souborů:
–*.java(zdrojový kód = čitelný text)
–*.class(bajtkód, nečitelný, pro spuštění je třeba JRE)
• Popř. ještě *.jar (což je ZIP archiv, kde je „zabaleno“ několik *.classa jiných souborů)
• K překladu programu může dojít ve dvou okamžicích:
–Před spuštěním programu (AOT = ahead-of-timecompilation)
• Výsledek překladu je třeba uložit do nějakého souboru (např. *.exe, *.class)
–V okamžiku spuštění/běhu programu (JIT = just-in-timecompilation)
• Výsledek překladu stačí mít v operační paměti (RAM), není nutné nic ukládat do souboru
• Umožňuje různé optimalizace kódu (např. využití možností procesoru, na kterém program právě běží, nebo využití znalosti, která část kódu se jak často využívá) pro zlepšení „kvality“ překladu a tím zvýšení výkonu programu
• Prodlužuje čas potřebný pro spuštění programu
• Přenositelnost programů
–Strojový kód je nepřenositelný
• Na jiné platformě fungovat nemusí, ať už z důvodu odlišného formátu souboru (PE/ELF), tak z důvodu odlišných možností hardware (procesoru)
–Zdrojový kód a bajtkódjsou přenositelné
• Ale pro svůj běh vyžadují speciální program (interpret nebo virtuální stroj / běhové prostředí)
• Rychlost běhu programu
–Strojový kód je (může být) nejrychlejší
• Může využít všech možností daného hardware (procesoru)
–Bajtkódve virtuálním stroji je pomalejší
• Je zde režie běhu samotného virtuálního stroje
• Kód pro virtuální stroj nemůže využít všech výhod aktuální platformy (virtuální stroj musí být schopen běžet na více platformách, takže může nabízet jen ty vlastnosti, které jsou pro všechny podporované platformy společné)
–Interpretace je (obvykle) nejpomalejší
• Zdrojový kód má strukturu vzdálenější stroji (než bajtkód)
• Pro řadu programovacích jazyků lze použít (se používá) více uvedených metod
–Java: bytecodea dále běh na virtuálním stroji nebo JIT kompilace
–JavaScript: tradičně interpretovaný, ale v nových verzích webových prohlížečů probíhá JIT kompilace
–PHP: tradičně interpretovaný, ale existují i překladače do bytecode(a dále virtuální stroj nebo JIT kompilace)
–Python: bytecodea virtuální stroj (CPython); JIT kompilace (PyPy)
• Android verze 1.0–2.1
–Programátor napsal zdrojový kód v jazyce Java (*.java)
–Ten se běžným překladačem přeložil na bajtkódpro JVM (*.class)
–Ten se programem „dx“ přeložil na bajtkódpro virtuální stroj Dalvik(*.dex= DalvikExecutable)
• Dalvika JVM se liší instrukční sadou, typem stroje (stack/register) atd., Dalvikje optimalizovaný pro mobilní zařízení (potřebuje málo paměti apod.)
• Android verze 2.2–4.4
–Dalvikprovádí JIT kompilaci, aby programy běžely rychleji
• Android verze 5.0 („Lollipop“)
–Dalvikje nahrazen ARTem(ART = Android Runtime)
• ART provádí AOT kompilaci (v okamžiku instalace aplikace), což dále zvyšuje výkon; používá se souborový formát
ELF (jako v Linuxu)
Syntax = pravidla zápisu
• Sémantika = význam zápisu
• RFC 5322 (Internet MessageFormat)
–Addressspecification
• http://tools.ietf.org/html/rfc5322#section-3.4
•E-mailová adresa má 3 části:
–Lokální část (např. název schránky)
• Může obsahovat jen některé znaky
–Určitě lze a–z, 0–9, tečku
–Určitě lze některé další znaky (pomlčku, …) a určitě nelze některé „divné“ znaky (např. s diakritikou)
»To je třeba nastudovat z norem (RFC)
–Určitě nelze mezeru (jinak nepoznám konec adresy)
–Určitě nelze „@“ (jinak nepoznám konec lokální části)
–Znak „@“
–Doménové jméno (serveru)
• Platí obecná pravidla pro zápis doménových jmen
–Viz příslušné normy (RFC)
• Popis syntaxe na předchozím snímku je špatně
–Lokální část může obsahovat mezeru i zavináč
–Tečka v lokální části může být jen „uvnitř“ (ne na krajích)
–Je možné použít skoro libovolný znak z Unicode*
• Platné e-mailové adresy: hodne.dlouha.lokalni.cast@dlouha.domena.example.com "martintrcka"@example.com
" "@example.org "martin@vsmiep.cz"@example.com
!#$%&'*+-/=?^_`{}|~@example.org "()<>[]:,;@\\\"!#$%&'*+-/=?^_`{}| ~.a"@example.org üñîçøðé@üñîçøðé.com
* Dle Wikipedie (v RFC 5322 jsem to nenašel, asi to bude v jiné normě). Všechny výše uvedené příklady jsou převzaty (a případně mírně upraveny) z článku http://en.wikipedia.org/w/index.php?title=Email_address&oldid=597633294#Examples5. 3. Kompletní zápis adresy
• Může obsahovat i jméno:
<martin.trcka@vsmie.cz> Trcka<martin.trcka@vsmie.cz>
"Martin Trcka" <martin.trcka@vsmie.cz> "Dwayne\"TheRock\" Johnson" <r@rock.cz>
• Dále může:
–Obsahovat komentář (v kulatých závorkách), být rozdělen na více řádků nebo obsahovat tzv. bílé znaky (whitespace)
• http://tools.ietf.org/html/rfc5322#section-3.2.2
• http://cs.wikipedia.org/wiki/Bílý_znak
–Být zapsán podle zastaralých (obsolete), volnějších pravidel
• http://tools.ietf.org/html/rfc5322#section-4
• Syntakticky správné e-mailové adresy, ale sémanticky špatné:
• Schránka s tímto jménem neexistuje
• Ani jedna z uvedených domén neexistuje
• Špatné rodné číslo (i když formát zápisu je v pořádku):
–561332/1234
• Špatná IP adresa (i když formát zápisu je v pořádku):
–192.168.0.315
1. Spousta věcí vypadá jednoduše, ale má-li být popsána přesně, je to složité (viz RFC)
–Počítač (stroj) ale potřebuje přesný popis, který zahrnuje všechny možnosti (i výjimečné)
2. Pro funkční komunikaci dvou programů je důležité, aby byla ustanovena pravidla komunikace
–Protokol (síťový), rozhraní (API), formát (souboru)
3. Kontrola (validace) vstupů od uživatele je těžká
–Programátor může snadno udělat chybu
• Nemalá část bezpečnostních chyb je tohoto typu
–Rada: použít knihovny, kde už je toto naprogramované
4. Samotná kontrola syntaxe nemusí stačit
–Někdy může být nutná i kontrola „významu“
Syntaktická analýza (parsing)
Syntaxe vs. sémantika(C#)
Syntakticky je program v pořádku, ale proměnná „pocet“ není nikde použita.
Syntakticky je program v pořádku, ale proměnná „vtup“ (překlep) neexistuje.
IDE
•Integrateddevelopmentenvironment(IDE)= integrované* prostředí pro vývoj (software)
• Může zahrnovat:
–Editor kódu (zvýrazňování syntaxe aj.)
• Prohlížeč objektů, prohlížeč hierarchie tříd, …
–Překladač / interpret
• Nástroje pro řízení překladu (různé platformy atd.)
–Nástroje pro ladění (debugger)
–Nástroje pro návrh GUI, testování, …
• Příklady pokročilých funkcí viz např. http://www.microsoft.com/visualstudio/cze/products/compare#feature-chart- heading
* Integrovaný = tvořící vzájemně propojený funkční celek
• VisualStudio (Microsoft)
• Eclipse
• IntelliJIDEA
• NetBeans
• JDeveloper(Oracle)
• Starší:
–Turbo Pascal, Delphi, C++Builder(Borland), …
• Zvýrazňování syntaxe
• Doplňování kódu
• Propojení s nápovědou
–F1 zobrazí nápovědu dle kontextu (pozice kurzoru)
• Dále:
–Operace ve více souborech najednou
–Pokročilé vyhledávání (např. regulární výrazy)
–Refactoringkódu
Zvýrazňování syntaxe(syntax highlighting)
Různé syntaktické prvky (proměnné, klíčová slova, textové řetězce atd.) mají různý vzhled, typicky různou barvu písma.
Doplňování kódu(codecompletition)
Napovídání názvů proměnných, funkcí, metod atd. podle kontextu (souvislostí), popř. včetně vysvětlivek. Regulární výrazy(regularexpressions)
• Speciální „vzory“ (zápisy) pro vyhledávání složitějších textových výrazů
–Existují různé jazyky pro zápis regulárních výrazů (POSIXové/Unixovéregulární výrazy, Perlovskéregulární výrazy, …)
• Příklady:
Agent 00[1-7] Agent 001, Agent 002, …, Agent 007
Colou?r Color, Colour
Hurá+ Hurá, Huráá, Hurááá, Huráááá,…
([A-Z]):\1 A:A,B:B, C:C, D:D, E:E, …
Debugger
• Nástroj (program) pro hledání chyb vprogramech (bug= chyba)
–Podrobněji na příští přednášce
• Pro práci (zejména) v týmu se hodí nástroje pro:
–Řízení týmových projektů
• Plánování (dle různých metodik), správa členů projektu, sledování průběhu, vykazování,
• Komunikace členů týmu (text, hlas, video)
–Sdílení a správu verzí (zdrojových kódů aj.)
–Správu sestavení (build)
–Správu testování
–Správa dokumentace (generování částí dokumentace)
–Modelování, diagnostiku, nasazení/publikování, …
• Příklad komplexnějšího nástroje:
–Team FoundationServer (Microsoft)
• http://www.visualstudio.com/cs-cz/products/tfs-overview-vs#Fragment_ProductFeatures
Správa verzí(versioncontrol, revisioncontrol)
• Správa změn ve zdrojových kódech programu
–Popř. i v dokumentaci, konfiguračních souborech, datových zdrojích atd.
• Příklady výhod:
–Řízení přístupu více programátorů k jednomu kódu
–Možnost návratu ke starší verzi kódu
• Např. „ještě včera to fungovalo“
–Možnost souběžného vývoje dvou (více) verzí programu
• Např. ve „stabilní“ verzi se opravují chyby, zatímco ve „vývojové“ verzi už se zkoušejí nové funkce
• Příklady specializovaných programů:
–CVS (ConcurrentVersionsSystem), Subversion(svn), Git, Mercurial, Microsoft VisualSourceSafe, …
• Nástroje, které z komentářů ve zdrojovém kódu umí vygenerovat (část) dokumentace
–Dokumentační komentáře musí dodržovat určitá pravidla zápisu (aby se odlišily od běžných komentářů)
–Výsledná dokumentace může být provázána hypertextovými odkazy (formát HTML)
–Příklady: Javadoc(Java), Doxygen(C++, Java, PHP, Python, …)
• Příklad zdrojového kódu s dokumentačními komentáři:
–http://www.docjar.net/html/api/java/util/Collections.java.html
• Příklad vygenerované dokumentace:
–http://docs.oracle.com/javase/7/docs/api/
• Vlevo nahoře klikněte na java.utila pak vlevo dole v části Classesna Collections:vpravo bude odpovídající
dokumentace
Platforma (počítačová)
• Souhrn prostředků (HW i SW), které slouží jako „základna“ pro běh programů
• Může zahrnovat:
–Hardware, zejména procesor
• Jakou instrukční sadu používá
–Operační systém
• Které funkce, resp. systémové knihovny program vyžaduje
–Aplikační prostředí
• Např. framework, který program využívá
• IA-32 (Intel Architecture, 32-bit), též x86
–Pojmenování „x86“ vychází z označení prvních Intel procesorů této architektury: 80286, 80386, 80486
–Nejen Intel, ale i AMD, VIA Technologies nebo Transmeta
• IA-64 (Intel Architecture, 64-bit)
–Intel Itanium(od roku 2001), hlavně servery
• Podporuje např. Windows XP 64-bit Edition
• x86-64, též x64, AMD64, Intel 64
–64bitové rozšíření instrukční sady IA-32
–Většina dnešních „běžných“ počítačů
• Architektura ARM (mobilní telefony, televize, …)
• Herní konzole (Playstation, Xbox, Wii, …)
• PowerPC(Apple Macintosh do roku 2006, nyní už x86)
• Speciální počítače (mainframe, superpočítače, …)
• Nejen instrukční sada procesoru, ale i:
–Výkon procesoru / grafické karty
–Množství dostupné paměti (RAM, HDD)
–Možnosti výstupních zařízení
• Rozlišení a poměr stran displeje, max. počet barev
–Možnosti vstupních zařízení
• Klávesnice / dotykový displej / hardwarová tlačítka / polohovací zařízení (myš, touchpad, Kinect, …)
• U různých stolních počítačů můžou být tyto charakteristiky podobné, ale u herních zařízení (konzolí) a přenosných zařízení (chytrých telefonů, tabletů) už je situace značně odlišná
• Windows (Microsoft)
• Mac OS (Apple)
• Linux, FreeBSD, …
• Unix, Solaris, OS/2, AmigaOS, …
• Mobilní telefony:
–Android (Google)
–iOS(Apple)
–Windows Phone(Microsoft)
–BlackBerryOS
–Symbian(Nokia)
• Knihovna funkcí, které tvoří základ pro vývoj software
–Obvykle obecné funkce, často i obecná „kostra“ programu –funkce specifické pro cílovou aplikaci nutno
doprogramovat
• Příklady frameworkůpro tvorbu webových aplikací:
–jQuery(Javascript), NetteFramework (PHP), ZendFramework (PHP), Ruby on Rails, ASP.NET MVC Framework, Spring(Java), Django(Python)
• .NET Framework (Microsoft), Mono (open sourceimplementace)
• Java platform
• Adobe Flash, Adobe Shockware, Adobe AIR
• Silverlight(Microsoft)
• Qt, GTK (tvorba GUI)
• Dva pohledy:
–Programátor: co je v rozporu se specifikací programu
–Uživatel: co funguje jinak, než by chtěl
• Ideální by bylo mít tyto pohledy v souladu (tj. aby specifikace zachycovala to, co uživatel chce)
–Ale ne vždy se to podaří
• Může dojít i k hádkám o to, zda dané chování programu je chyba, nebo ne (tedy kdo zaplatí opravu)
• Člověk(aneb každý dělá chyby)
–Co zvyšuje míru chyb?
• Nedostatečná kvalifikace a/nebo zkušenost
• Časový tlak (honí se termín)
• Únava (přepracování)
• Špatné pracovní prostředí (vyrušování, nepohodlná židle, velká teplota v místnosti, nedostatek tekutin, špatné osvětlení, …)
• Malá motivace (např. nezáleží mu na kvalitě)
• Mimopracovní (např. rodinné) problémy
• Komunikace (mezilidská)
–Zadavatel ↔ realizátor
–Vedoucí týmu ↔ programátor
Špatná analýza požadavků
–Podcenění složitosti projektu
• Z toho plynoucí časový tlak, přepracování, …
–Nedostatky v zadání
• Aplikace je perfektní (dle zadání), ale skuteční uživatelé chtěli (potřebovali) něco jiného
• Nové technologie
–Nevyzkoušené funkce nebo celé knihovny
• Chvíli trvá, než se programátor s novou technologií seznámí a než ji umí správně použít
• Nové projekty obsahují větší míru chyb (tvůrce se v prvotních fázích soustředí na funkce, projekt není otestován na velkém vzorku uživatelů), dokumentace může být nedostatečná, …
• Aritmetické chyby
• Logické chyby
• Jazykové omyly
• Chybná práce s pamětí
–Přetečení zásobníku, únik paměti
• Chyby souběžných systémů
–Deadlock, racecondition
• Další chyby
–Výkon, rozhraní, tým
• Dělení nulou
–intx = 300000; // Int32inty = x * x; // y je −194313216;
• Zaokrouhlovací chyby
–double x = 0.1; double y = (0.1 + 10) -10;Console.Write(x == y); // False
• Chyba „plus/minus 1“
–Příklad:Mějme čísla 7, 8, 9, …, 22, kolik těch čísel je?22 − 7 = 15?Kdepak, je jich 22 − 7 + 1 = 16.
• Nekonečný cyklus
–// v cyklu zapomeneme zvýšit// proměnnou i o jednainti = 1;while(i != count){………}
• Nebo omylem nastavíme countna záporné číslo
• Operátor !=znamená nerovnost (opak ==)
• Nekonečná rekurze
• if(x = 5) …
–Neprovede test, zda je hodnota proměnné xrovná 5 (to by v závorce muselo být x == 5), ale provede přiřazení hodnoty 5 do proměnné x
• Častá u jazyků, které umožňují přímou práci s pamětí (např. jazyky C, C++)
–Program požádá operační systém o 16 bajtů paměti.Omylem do paměti zapíše 17 bajtů.Zápis posledního bajtu může způsobit:
• Chybu v přístupu do paměti (porušení přístupových práv), což typicky znamená pád programu
• Přepis tam uložené hodnoty (např. proměnné), což může vyústit vprakticky cokoli (divné chování programu, pád programu, …)
–Pokud jsou zapisovaná data (17 bajtů) pod kontrolou uživatele (jde např. o zadávaný vstup), pak lze často tuto chybu využít k narušení bezpečnosti daného programu
• Únik paměti (memoryleak)
–Program požádá OS o 1 MB paměti.Později program tuto paměť přestane využívat, ale zapomene ji „vrátit“.
• Pokud program takto žádá o paměť (a nevrací ji) opakovaně, pak program zabírá v operační paměti stále více a více místa… (až místo dojde)
Příklad: Mozilla Firefoxverze 15 (z 28. 8. 2012) obsahuje funkci, která zmírňuje dopady úniků paměti zásuvných modulů (plug-inů). Vývojáři Firefoxutotiž zjistili, že úniky paměti způsobují z velké části právě zásuvné moduly (tj. cizí programy), ne samotný Firefox. Podrobnosti viz http://blog.mozilla.org/nnethercote/2012/07/19/firefox-15-plugs-the- add-on-leaks/
• Chyby, ke kterým může dojít v případě, kdy běží více programů (popř. vláken*) najednou
–Víceprocesorové počítače (multiprocessing)
–Víceúlohovéoperační systémy (multitasking)
–Vícevláknovéprogramy (multithreading)
–Distribuované systémy
• Programy běží na různých počítačích, ale používají společné zdroje (zejména paměť)
• Příklady chyb:
–Dead-lock(uváznutí)
–Racecondition(souběh)
• Řešení:
–Synchronizace (koordinace běhu)
* Vlákno (thread) je část programu (tj. posloupnost instrukcí), která může běžet samostatně
• Deadlock(uváznutí)
–Program A čeká, až program B dokončí nějakou akci. Zároveň ale program B čeká na dokončení akce programu A
• Takto může čekat i více programů
–Výsledek: Všechny programy „zamrznou“
–Chyba, kdy výsledky závisí na načasování jednotlivých instrukcí programu
–Typický výsledek: někdy se stane něco jiného, než co programátor očekává Racecondition(příklad)
• Program zvyšující čítač X:
–Načti X (z databáze, ze souboru, z paměti)X = X+ 1Ulož X
• Při vícenásobném souběžném použití (spuštění) programu ale může nastat tato situace:
–Kód byl proveden 2×
–Ale čítač byl zvýšen jen 1×
Čas | X | Program1 | Program 2 |
1 | 50 |
| Načti X (50) |
2 | 50 |
| X =X+ 1 (51) |
3 | 50 |
| Načti X (50) |
4 | 50 |
| Ulož X (51) |
5 | 51 |
| X =X + 1 (51) |
6 | 51 |
| Ulož X (51) |
7 |
| 51 |
|
• Chyby ve výkonu programu
–Nadměrné využití procesoru nebo paměti
• Závisí na zvolených datových strukturách a algoritmech
• Chyby při použití rozhraní
–Nesprávné použití API
–Nesprávná implementace síťového protokolu
• Chyby související s prací v týmu
–Např. nesprávné informace (komentáře v kódu, dokumentace, popis API)
• Zastaralé, nekompletní nebo zavádějící informace
• Nápad: Co udělat program Tester, který zkontroluje můj program (např. jeho zdrojový kód), zda je v pořádku?
• Problémy:
–U netriviálních programů existuje velké množství různých vstupů (a velké množství „průchodů“ programem) kontrola všech možností by zabrala hrozně moc času (miliardu let?)
–Program Tester, který by zkontroloval správnost výsledku, obecně nelze vytvořit
• Nelze totiž vytvořit ani jednodušší program –takový, který zjistí, jestli vůbec můj program vydá nějaký výsledek, tj. jestli můj program vůbec skončí (jde o tzv. problém zastavení)
• Lze udělat obecný program Tester, který rozhodne, zda se program P se vstupem V zastaví (nebo zda poběží donekonečna)?
–Vstupy: P (kód programu), V (vstupy programu P)
–Výstup: „Ano“ (program P se na vstupu V zastaví), nebo „Ne“ (nezastaví)
• Alan Turing(1936): Ne
–Tedy ani tak jednoduchý problém nelze vyřešit (označuje se za nerozhodnutelný)
• Jinými slovy: zacyklení programu není algoritmicky detekovatelné (a to ani v případě, že známe všechny vstupy
programu)
Reprezentace (odbočka)
• Základní myšlenka: Vše v počítači můžeme považovat za číslo
–Vše má v počítači binární reprezentaci, což je v podstatě jen zápis čísla (i když někdy obrovského čísla, s mnoha a
mnoha ciframi)
• Např. text tvořený 8 znaky je (při použití 1bajtového kódování znaků) vlastně 8bajtové číslo
• Např. rastrový obrázek tvořený 4 ×4 = 16 pixely je (při barevné hloubce 3 bajty) vlastně 48bajtové číslo
–Tedyvšechny vstupy(parametry) programu, výstupyprogramu i programsamotný (ať už zdrojový kód, tj. text, nebo binární kód) jsou jedna a tatáž věc, číslo (liší se jen hodnotou)
• Důkaz sporem:
–Předpokládám opak a dojdu k nesmyslnému výsledku (ke sporu)
• Tedy nechť program Testerexistuje
–Tester(X, V) tedy vrátí „Ano“, když program X se vstupem V skončí (jinak vrátí „Ne“)
• Vyrobím program AntiTesters jediným vstupem X
–Program AntiTesterbude fungovat takto:
• Spustí program Tester(X, X)a dále:
–Když je návratová hodnota „Ano“ (= program X se vstupem X skončí), tak se program AntiTesterúmyslně zacyklí (neskončí)
–Když je návratová hodnota „Ne“ (= program X se vstupem X neskončí), tak program AntiTesterskončí (s libovolnou návratovou hodnotou)
• Co se ale stane, když spustím program AntiTesterse vstupem AntiTester?
–Může buď skončit, nebo neskončit (zacyklit se)
a) Když AntiTesterskončí, tak dle definice AntiTesterumuselo dojít k situaci, že volání Tester(AntiTester, AntiTester)vrátilo „Ne“, což ale znamená (dle definice programu Tester), že program AntiTestersparametrem AntiTesterneskončí, tedy spor s předpokladem a)
b) Když AntiTesterneskončí, tak dle definice AntiTesterumuselo dojít k situaci, že volání Tester(AntiTester, AntiTester)vrátilo „Ano“, což ale znamená (dle definice programu Tester), že program AntiTestersparametrem AntiTesterskončí, tedy spor s předpokladem b)
–V obou případech jsme došli ke sporu, tedy náš předpoklad (že program Testerexistuje) musel být mylný
• Překladač
–Odhalí syntaktické chyby
–Odhalí některé sémantické chyby (nepoužitá proměnná apod.)
–Výpisy (na obrazovku, do souboru), které informují o stavu programu
• Post-mortemdebugging(„po smrti“)
–Při „pádu“ programu může operační systém uložit obsah paměti programu (v okamžiku pádu) do souboru (dumpfile,
• Lze později obsah souboru analyzovat: zjistit stav programu (hodnoty proměnných, na kterém příkazu program zhavaroval, s jakými parametry byla daná funkce volána atd.) v okamžiku pádu
• Krokování, breakpoint(viz dále)
• Defenzivní programování(„obranné“)
–Programování dle hesla „nevěř nikomu“ (ani sobě
–Např. důsledná kontrola všech vstupních hodnot funkce
• Často se využívá assertions(viz dále)
• Testování
–Spustím výslednou aplikaci a zkouším všechny funkce, různé divné vstupy atd. a sleduji, zda se program nechová nestandardně (špatné výsledky, spadne atd.)
–Napíšu si program, který testování udělá za mě (lze volat různé funkce programu s různými parametry, lze
„naskriptovat“ i klikání v GUI)
• Napsané testy lze hromadně spouštět po každé změně kódu a kontrolovat tak, zda změna něco „nerozbila“
• Unit testing= testování nezávislých částí (jednotek) programu (kódu)
Assertion
• Výraz typu ano/ne, kterým programátor vyjadřuje své očekávání (předpoklad)
–Pokud výraz neplatí, je program ukončen
• Příklad použití:
Pozor: Assertionneslouží pro zvládnutí „chyb“ uživatele programu, když např. uživatel zadá „divný“ vstup –na chyby uživatele totiž neumí assertionnijak rozumně reagovat (nemá žádné tělo). Assertionslouží pro odhalování chyb programátora, např. nesprávné volání funkce, neohlídání si určité krajní situace apod.
• Krokování
–Provádění programu krok po kroku (příkaz po příkazu)
• Lze si prohlédnout stav programu (např. hodnoty proměnných) v daném okamžiku
• Breakpoint
–Místo (point) v kódu programu, kde se má běh programu zastavit (break)
• Lze dále provádění programu krokovat
• Co je to za divná otázka, existují snad důvody, proč nalezenou chybu neopravit?
• Ano, existují:
–Oprava chyby může do programu zavléct jinou, mnohem závažnější chybu
• Např. vyřeším špatné zobrazování ikony, ale program začne padat
–Oprava chyby stojí čas a programátory (tj. peníze)
• A taky s vydáním Windows 95 nelze čekat až do roku 1997
• Příklad:
–Na začátku projektu je laťka na nule:
• Opravují se všechny chyby, které jsou nahlášeny
–Termín odevzdání projektu se blíží, takže „zvedáme laťku“:
• Opravují se jen chyby, které způsobují ztrátu dat uživatele (nebo horší)
–Termín se ještě více blíží, takže „zvedáme laťku“:
• Opravují se jen chyby, které znamenají smrt člověka* –Termín už je za dveřmi, takže „zvedáme laťku“:
• Opravují se jen chyby, které znamenají smrt blonďatých modrookých holčiček**
* V řadě oblastí (lékařství, vojenství, fyzikální nebo chemické pokusy, řízení strojů atd.) se tohle skutečně může stát
** Tohle už je vtip
• Je tedy zcela běžné, že firma vydá program, který obsahuje chyby, o kterých firma ví –Mělo by ale jít o méně závažné chyby
• Uživatel se často smíří s pár menšími chybami, pokud má program pro něj znatelný přínos
Například program Microsoft Word má v některých situacích problémy svykreslováním dokumentu (např. některé řádky jsou vidět „dvojmo“), ale stačí posuvníkempohnout nahoru a dolů a chyba je pryč. Jde tedy o malou chybu a obecně má pro mě tento program velký přínos, takže jsem ve výsledku spokojen.
• Aplikace pro evidenci chyb (požadavků*) –Zadávání chyb
• Prostředek pro komunikaci mezi zákazníky (zadavateli chyb), vývojáři (programátory), vedoucími projektů, … –Sledování stavu chyb
• Přiřazování chyb vývojářům, sledování počtu chyb, nastavování priority chyb, přístupová práva k popisům chyb (bezpečnostní chyby)
• Příklady:
–Bugzilla, Mantis, …
* Požadavky jsou i návrhy na vylepšení, nejen chyby
• Co má obsahovat popis chyby?
• Odpověď získáme, když se zeptáme: K čemu se popis chyby použije?
–Typicky se programátor bude snažit podle toho popisu chybu znovu vyvolat –aby ji mohl prozkoumat
• Popis chyby by tedy měl obsahovat:
–Popis situace popř. aktivity tak, aby bylo možné chybu znovu vyvolat (zreprodukovat)
• Typicky kroky, které k chybě vedou
• Okolnosti (použitý program, platforma atd.)
–Např. řada uživatelů Windows zapomene zmínit, že používají Windows (když chyba může být závislá na operačním systému)
–Popis, jak by to mělo být správně
• Ne vždy je jasné, co přesně uživateli na popsané situaci vadí, nebo jakou změnu udělat, aby to už uživateli nevadilo.
50.a 60. léta FORTRAN, LISP, COBOL, ALGOL,BASIC
1968-1979 Simula(OOP), Logo, Pascal
C(DennisRitchie, KenThompson) Smalltalk, Prolog, Scheme
80. léta C++, Objective-C
Eiffel, Erlang, Perl
90. léta Haskell, Python, VisualBasic, Ruby, Lua
Java, Delphi(ObjectPascal)
2000 a později ActionScript(FlashPlayer), C#, Clojure,Dart
• Nižší (nízkoúrovňový, low-level, strojově orientovaný) jazyk
–Žádná nebo malá míra abstrakce od hardware (procesoru), tj. těsně spjatý s hardware
• Překlad do strojového kódu typu 1 : 1 (jeden příkaz jazyka odpovídá jedné strojové instrukci)
–Např. strojový kód, assembler
• Vyšší (vysokoúrovňový, high-level) jazyk
–Vyšší míra abstrakce
• Překlad typu 1 : N (jeden příkaz odpovídá více instrukcím)
–Např. vše ostatní
• Výhody nižších jazyků:
–V některých situacích (jednoduché čipy, robůtci atd.) jediná možnost programování
• Není-li dostupný překladač/interpret
–Větší výkon programu
• Nižší nebo žádná režie (žádné zbytečné instrukce) –Větší kontrola nad tím, co program dělá
• Výhody vyšších jazyků:
–Jednodušší (tj. levnější) tvorba programů
• Jazyky obsahují prostředky usnadňující programování: proměnné, datové struktury, řídící struktury, metody, objekty,
–Lepší přenositelnost programů
• Funkčnost programů na širší skupině hardware
• Paradigma:
–Příklad, vzor
–Soubor předpokladů, na kterých je vybudována určitá teorie
–Způsob pohledu na určité jevy z pozic ucelené teorie
–Soubor předpokladů vytvářející rámec pro existenci určitého jevu
• Programovací paradigma
–Základní programovací styl
• Imperativní (příkazové)
–Nestrukturované (např. BASIC)
–Strukturované
• Procedurální (např. Pascal, C)
• Objektově orientované (Java, C++, Objective-C, C#, …)
• Deklarativní
–Logické (např. Prolog)
–Funkcionální (např. Lisp, Scheme, Haskell)
Řada jazyků podporuje několik paradigmat zároveň ČLOVĚK
Deklarativní (logický nebo funkcionální) jazyk
• Příkazový objektový: C++, Python, C#, Java
• Příkazový strukturovaný: Pascal, C
• Příkazový nestrukturovaný: BASIC
• Jazyk symbolických instrukcí (assembler)
• Strojový kód
STROJ
Každý jazyk má své výhody a nevýhody, tj. neexistuje „obecně nejlepší“ jazyk, může však existovat jazyk nejlepší pro danou situaci, pro dané použití
Ukážeme si
• Instrukce pro hardware (procesor)
• Typy instrukcí (vonNeumann):
Procesor –řídící jednotka Dekóduje instrukce, úkoluje ostatní jednotky
Instrukce skoku (jump)
Procesor –ALU Aritmetické (+ − · / …) a logické (=< AND NOT XOR
…)instrukce
Paměť(operační) Instrukce zápisu dopaměti (write, store) a načítání (read, load)
z paměti
Vstupní a výstupní jednotky Instrukce čtenídat ze vstupů a posílání dat na výstup
• Paměti přímo v procesoru
–Malé paměti
• Např. architektura x86 používá několik desítek 32bitových registrů, tj. celkem desítky bajtů (naproti tomu RAM má miliardy bajtů)
–Velice rychlé paměti
–Používají se jako vstupy a výstupy při provádění instrukcí
• Např. instrukce sčítání: oba sčítanci jsou v nějakých registrech a výsledek (součet) se také uloží do registru
–Pro práci s registry se obvykle používají jiné instrukce než pro práci s operační pamětí
• Jednotlivé registry jsou identifikovány např. svým pořadovým číslem
• Paměť je rozdělena na „přihrádky“ pevné velikosti (např. 1 bajt)
–Přihrádku lze identifikovat pomocí jejího pořadového čísla, tzv. adresy
• Instrukce zápisu do paměti má dva parametry:
–Adresa (kam zapisovat)
–Data (co zapsat)
• Instrukce čtení z paměti má dva parametry:
–Adresa (odkud číst)
–Kam uložit načtená data (např. do kterého registru)
Adresa … 834 835 836 837 838 839 …
Hodnota (16) 4D 41 68 6F 6A 00 6B 23
Ukázka: architektura MIPS I
• Procesor má 32 registrů
–Na identifikaci registru tedy stačí 5 bitů (25= 32)
• Každá instrukce má 32 bitů
–Příklad instrukce (mezerami jsou odděleny jednotlivé logické části instrukce):000000 00100 00101 00010 00000
100000
Význam instrukce: Hodnota opcode(nejvyšších 6 bitů instrukce: 000000) určuje, že jde o instrukci, která má pět parametrů: tři 5bitové identifikátory registrů (rs, rt, rd), 5bitová velikost posunu (shamt) a 6bitové upřesnění funkce (funct). Hodnota funct(100000) určuje, že jde o operaci sčítání registrů. Sčítanci jsou v registrech č. 4 a 5 (rs: 00100, rt: 00101), výsledek sčítání se má uložit do registru č. 2 (rd: 00010). Hodnota posunu (shamt) se u operace sčítání registrů ignoruje. Smysl této instrukce by se tedy dal symbolicky zapsat takto: reg2 = reg4 + reg5
• Výhody:
–Někdy jediná možnost programování
–Možnost maximálního výkonu programu
–Maximální kontrola nad tím, co program dělá
• Nevýhody:
–Náročná tvorba programů (primitivní prostředky)
–Nepřenositelnost programů (obecně)
• Použití:
–Jednoduché čipy, robůtci, hardware obecně
• Textový zápis jednotlivých strojových instrukcí
–Druh operace slovně, např. mov= operace přesunu dat (move)
–Identifikace registru názvem, např. registr eax(místo 00001)
–Pro číselné hodnoty lze použít desítkový nebo šestnáctkový zápis (místo binárního)
• Trochu matoucí terminologie (v praxi):
Anglicky (teoreticky) Assemblylanguage Assembler
Česky(teoreticky) Jazyk symbolických adres (jazyk symbolických instrukcí)
Assembler
Česky(prakticky) Assembler Překladač
• Textové řetězce (string) můžou být různě dlouhé (různý počet znaků/bajtů) –Jak poznat, kde (v paměti) řetězec končí?
• Obvykle se používá jedno z následujících řešení:
–Ukládá se i délka řetězce
• Použití: jazyk Pascal (první bajt textu = délka)
• Nevýhoda: řetězec má omezenou délku (255 znaků)
–Použije se značka, která znamená „konec textu“
• Např. bajt s hodnotou nula (00000000)
• Použití: jazyk C
• Nevýhoda: uvnitř řetězce se daná značka nesmí vyskytovat
; counts a zero terminated ASCII string
; to determine its size
; in: eax= start address of the string
; out: ecx= the length of the string
zstr_count: movecx, -1
.loop:
incecx
cmpBYTE [eax+ ecx], 0
jne.loop
.done:
Ret
Ukázka: assembler x86
Zjistí délku textového řetězce, kde ukončovacím znakem je znak s ASCII kódem 0 (nula)
Vstup: V registru eaxje uložena adresa začátku (1. znaku) textového řetězce Výstup: Na konci má být v registru ecxvýsledek (délka)
Ukázka: assembler x86
• Výhody oproti strojovému kódu:
–Jednodušší tvorba programů –přehlednější (textový) zápis
–Nutnost překladače do strojového kódu
• Použití:
–Jednoduché čipy, robůtci, hardware obecně (ovladače zařízení, firmware, BIOS, čipy v pračkách, autech, senzorech
atd.)
–Když je kriticky důležitý výkon (vědecké výpočty, real-timesystémy, real-timehry, dekódování videa, šifrování, komprese dat, …)
–Když je důležitá maximální kontrola nad činností programu (simulátory, virtualizace, debuggery, reverzní inženýrství,
sebe-modifikující programy, viry, …)
• Je bližší člověku (jeho myšlení) než assembler
–Proměnné (a někdy i datové typy)
–Řídící struktury: cykly (FOR), podmínky (IF), …
–Složitější výrazy (x + 5 >= (y + 7) * z)
• Implementace (principiálně):
–Proměnné = instrukce zápisu do (čtení z) paměti
–Řídící struktury = instrukce skoku
–Složitější výrazy = posloupnost více instrukcí Ukázka: BASIC
• Příklad běhu programu:
What is your name: Mike Hello Mike
How many stars do you want: 7
*******
Do you want more stars? yes How many stars do you want: 3
***
Do you want more stars? no Goodbye Mike
Poznámka: Ukázka odpovídá první generaci jazyka BASIC. V dalších generacích došlo k vylepšení jazyka o prvky strukturovaného a později i objektového (např. VisualBasic .NET) programování, také byla odstraněna nutnost číslování řádků.
• Výhody oproti assembleru:
–Jednodušší tvorba programů –proměnné (popř. datové typy), řídící struktury (FOR, IF, …), výrazy
–Překladač pro příkazový jazyk je složitější než pro assembler (překlad bude typu 1 : N), tzn. je menší šance, že bude
existovat
• Použití:
–Historie
–Dnes už je prakticky každý příkazový jazyk strukturovaný
–Algoritmus
–Proměnné a datové typy
• Typová kontrola, oblast platnosti, inicializace
–Metody (funkce a procedury)
• Parametry (předávání), návratová hodnota
• Návrh metody
• Algoritmus = postup řešení problému
• Vlastnosti algoritmu:
–Hromadnost(obecnost)
• Neřeší jeden konkrétní problém (např. největší společný dělitel čísel 35 a 20), ale celou třídu podobných problémů (např. největší společný dělitel čísel x a y)
–Determinovanost
• Každý krok algoritmu je přesně určen (determinován)
• Existují ale i nedeterministické algoritmy (např. pravděpodobnostní algoritmy, které se v některých krocích rozhodují náhodně)
–Konečnost
• Algoritmus skončí po konečném počtu kroků
–Resultativnost
• Algoritmus má nějaký výsledek (výstup)
• Zápis algoritmu:
–Přirozený jazyk
–Vývojový diagram
–Pseudojazyk
–Programovací jazyk
Vývojový diagram(algoritmus kontroly funkčnosti lampičky)
• Údaje = datové objekty
–Proměnná nebo konstanta
–Datový typ
• Programse skládá z deklarací a příkazů:
–Deklarace= určení významu identifikátorů (jmen)
–Příkazy= akce s datovými objekty nebo řízení výpočtu (větvení, cykly atd.)
Datový typ
• Má vliv zejména na:
–Množství zabrané paměti(kolik bajtů)
• Může záviset na uložené hodnotě (např. u textových řetězců)
–Možné hodnoty
• Např. jaké je minimum a maximum u celých čísel, jaká je přesnost u čísel desetinných atd.
• Některé typy mají vnitřní strukturu (položky, členské proměnné, např. typ Zlomekmá položky Čitatela Jmenovatel)
–Možné operace
• Např. sčítání u čísel, spojení u textových řetězců atd.
• A také efektivita (časová, prostorová) provádění různých operací
• Základní datové typy (umí je hardware, tj.procesor, viz také registry):
–Celá čísla (int, integer)
• Obvykle 8/16/32/64 bitů (má vliv na rozsah hodnot)
• Se znaménkem (signed), nebo bez (unsigned)
• Odvozené typy (tj. jen „převlečený“ integer): boolean, char, výčtový typ (např. pohlaví: muž [0], žena [1], neurčeno
[2]), ukazatel(pointer)
–Čísla s desetinnou čárkou (float, double)
• Obvykle 32/64 bitů (IEEE 754)
• Složitější datové typy
–Pole(obvykle homogenní –prvky stejného typu), vektory, spojové seznamy, zásobníky, matice, hašovacítabulky, …
–Struktury(obsahují prvky různých typů)
• Často i uživatelsky definovatelné
–Textové řetězce (string)
• Pozor: různá implementace v různých jazycích (tj. různé vlastnosti)
–Velká (popř. neomezená) čísla
• Viz např. http://en.wikipedia.org/wiki/Arbitrary-precision_arithmetic#Languages
–Objekty/třídy(viz Objektově orientované program.dále)
–Funkce(viz Funkcionální programovánídále)
• U řady programovacích jazyků je nutné u proměnné uvést její datový typ a ve výrazech nelze (neomezeně) míchat různé datové typy
–Např. C, C++, Java, C#, Pascal, … (často kompilované jazyky)
• Říká se, že takový jazyk má statickoutypovou kontrolu (už při kompilaci) a že má silnétypování (nelze míchat odlišné typy)
–Umožňuje zachytit (typovou) chybu brzy
• U řady jiných jazyků se datový typ proměnné neuvádí a lze vjednom výrazu míchat různé datové typy (např. číslo a
text)
–Např. JavaScript, PHP, Python, … (často interpretované jazyky)
• Říká se, že takový jazyk má dynamickoutypovou kontrolu (až při běhu programu) a že má slabétypování
–Snadnější psaní kódu (není nutné uvádět datové typy proměnných a ručně provádět konverze mezi typy)
x= "1" + 2
Silný Chyba při překladu (u operace „plus“ nelzemíchat textový řetězec a číslo)
Slabý "12"(číslo 2 se automaticky převede na textový řetězeca provede se spojení řetězců),
nebo 3(řetězec "1" se automaticky převede na číslo a provede se sčítání)
Typová kontrola (příklad 2) if (x=5) …
Výraz „x=5“ má typ„celé číslo“ (a hodnotu 5). Konstrukce ifale vyžaduje logickou hodnotu (true/false).
C,C++ Jazyk provede u konstrukce ifautomaticképřetypování zcelého čísla na logickou hodnotu (nenulové číslo true). Výše uvedený kód je tedy korektní a je ekvivalentní kódu: x=5; if(true) …
C#, Java Jazyk neprovádí automatické přetypování zčíselné hodnoty na logickou. Výše uvedený kód tedy překladač označí jako chybný.
Typová kontrola (příklad 3)
Graf vlevo ukazuje, které hodnoty jsou si rovné (operátor ==) v jazyce PHP. Pokud budeme míchat různé datové typy (číslo, logickou hodnotu, textový řetězec), pak dojdeme k překvapivému zjištění, že1 == True== "php" == 0
Logika operátoru == přitom dává smysl:
"" (prázdný řetězec) == False "abc" (neprázdný) == True Řetězec vs. číslo:
"1" == 1
"2" == 2 atd.
"nečíslo" == 0
Pro test rovnosti hodnoty a zároveň i datového typu má jazyk PHP operátor === (3 rovnítka)
Proměnné a datové typy (ukázka)
C, C++, Java, C# intx= 5;
Pascal var
x: integer; y: char; begin
…
x = 5;
…
end
Deklaraci typů (část var) je nutné uvéstještě před tělem programu (část begin… end)
PHP $x = 5; Proměnné sepoznají podle znaku $
Není nutné deklarovattyp
JavaScript,Python x =5; Není nutné deklarovattyp
Oblast platnosti proměnné
• Obecně:
–Lokální= platnost v omezené části kódu
–Globální= platnost v celém programu
• Různé jazyky ale lokálnost/globálnost chápou různě:
–Platnost v nějak vymezeném bloku kódu
–Platnost v jednom souboru
–Platnost v jednom modulu/unitu/balíčku (v jedné logickéjednotce programu)
–Jazyk PHP: explicitně globální proměnné (global$x) vs. implicitně globální (tzv. superglobální)
Vymezení bloku kódu (ukázka)Jazyk Příklad kódu Způsob vymezení
C, C++, Java, C#, PHP, JavaScript {
…
}
Pascal begin
…
end
Python deffoo(x):
if x == 0: bar()
baz() else: qux(x) foo(x -1)
Speciálními znaky (složené závorky)
Klíčovými slovy (begin, end)
Odsazením jednotlivých řádků kódu
• Jak proměnná (datový objekt) vznikne?
–Automaticky na začátku bloku, ve kterém je deklarovaná
• V některých jazycích až na řádku, kde je deklarovaná
–Ručně příslušným příkazem (např. new)
• Jak proměnná (datový objekt) zanikne?
–Automaticky na konci bloku
–Ručně příslušným příkazem (např. delete)
•Jakou hodnotu má proměnná na začátku?
–Námi definovanou (např. intx = 5;)
–Předem danou (viz specifikace daného jazyka)
• Obvykle nějakou neutrální, např. u čísel 0 (nula)
–Nedefinovanou (tj. libovolnou/náhodnou)
• Pokud jazyk povoluje použít neinicializovanou proměnnou (např. C, C++), pak je to poměrně nebezpečné
–U řady jazyků záleží i na datovém typu proměnné a také na tom, zda je proměnná lokální nebo globální
• Různé jazyky mají různá pravidla pro zápis identifikátorů (názvů proměnných, funkcí, datových typů atd.):
–Obvykle nesmí název začínat číslicí (aby se dal rozeznat od číselné konstanty)
• Případně se pro odlišení proměnné používá nějaký speciální znak (např. $)
–Záleží/nezáleží na velikosti písmen
–Název musí/nemusí začínat velkým/malým písmenem
–Jsou/nejsou povoleny znaky s diakritikou (á, č, ď, é, …)
–Které nepísmenné znaky jsou/nejsou povoleny (tečka, podtržítko, …)
• Pro dobrou čitelnost kódu je vhodné se držet zvyklostí daného jazyka (popř. dané knihovny, firemní kultury atd.) –Zápis může napovědět (rozlišovat), zda jde o proměnnou, konstantu, název funkce, název datového typu atd.
• Příklady zápisů:
old_HTML_file old-HTML-file OLD_HTML_FILE
oldHtmlFile OldHtmlFile
Některé typy zápisů mají i svůj název, např. Camelcasenebo Pascal case
• U rozsáhlých programů je problém, jak pojmenovat novou proměnnou (funkci, datový typ), aby nový název byl jedinečný (tj. nebyl stejný jako některý starý)
–Řešení č. 1: dlouhý název zahrnující např. i oblast užití proměnné (název části programu apod.), např.
SystemNumericsBigInteger
• Nepraktické –úmorné psaní, zmenšuje přehlednost kódu (moc dlouhé řádky/příkazy)
–Řešení č. 2: dlouhý strukturovanýnázev, např. System.Numerics.BigInteger
• Podpora: tzv. jmenný prostor (namespace)
• Skupina identifikátorů (nějak souvisejících)
• Příklad (C++): std::cout
–Existuje jmenný prostor „std“
• V něm existuje lokální identifikátor „cout“
• Příklad (C#): System.Numerics.BigInteger
–Existuje jmenný prostor „System“
• V něm existuje jmenný podprostor „Numerics“
–A v něm existuje lokální identifikátor „BigInteger“ Jmenný prostor (příklad, C#)
Návrh programu
• Rozdělit program na logické bloky (abstraktní příkazy), tzv. „metody“
–Každá metoda řeší nějaký podproblém
–Metody navzájem spolupracují
• Propojení metod: předáváním parametrů a návratových hodnot (popř. i jinak)
• Princip se označuje jako „Rozděl a panuj“ (latinsky divideet impera)
• Co programátora na metodě zajímá?
–Vstupymetody
–Tělometody (tj. co metoda dělá)
• Někdy i náročnost (časová, paměťová)
–Výstupymetody
• Vstupy metody:
–Parametrymetody
–Globální stav
• Globální proměnné
• Obsah paměti, disků (soubory), síťová komunikace, …
• Vstupní zařízení (myš, klávesnice, …)
• Výstupy metody:
–Návratová hodnota
–Výstupní parametry
–Změna globálního stavu (tzv. vedlejší efekty, side-effects)
• Glob. proměnné, paměť, zařízení (obrazovka, tiskárna, …)
Vstupy a výstupy: bestpractices
• Vstupymetody je nejlepší realizovat pomocí parametrů
–Protože parametry „jsou vidět“ (jak v deklaraci metody, tak při jejím volání)
–Že metoda čte i globální stav, to „vidět není“ (ani v deklaraci, ani při jejím volání)
• Je vhodné to tedy programátorovi sdělit jinak: názvem metody nebo to uvést v dokumentaci metody
• Výstupymetody je nejlepší realizovat pomocí návratové hodnoty
–Protože návratová hodnota „je vidět“ (viz výše)
–Pokud je výstupních údajů více, je možné použít vhodnou datovou strukturu nebo výstupní parametr(y)
–Změny globálního stavu (tzv. vedlejší efekty) „vidět nejsou“
• Sdělit jinak: názvem, v dokumentaci
• Deklarace= určení, že daná metoda existuje
–Jaký má název
–Jaké má parametry (popř. jejich datový typ)
–Popř. jaký typ má návratová hodnota
–Popř. další vlastnosti*
• Definice= určení těla metody (co dělá)
• U některých jazyků lze deklaraci a definici uvést zvlášť (v různých částech kódu)
• Některé jazyky (např. Pascal) rozlišují funkcia proceduru:
–Funkce má návratovou hodnotu
• Lze použít ve výrazu (např. if(max(x, y) > 5) …)
–Procedura nemá návratovou hodnotu
• Nelze ji použít ve výrazu
• Svůj výstup realizuje buď pomocí výstupních parametrů nebo změnou globálního stavu
• A v některých jazycích (C++, C#, PHP, …) je to jedno a obojímu se říká funkce
–Rozlišení se dělá např. speciálním typem návratové hodnoty (např. void)
Funkce (ukázka)Jazyk Příklad kódu
C++, Java, C# intscitani(intx, inty)
{
return x + y;
}
Pascal functionscitani(x: integer, y: integer): integer; begin
scitani:= x + y; end
Python defscitani(x, y): return x + y
Procedura (ukázka)Jazyk Příklad kódu
C++, Java, C# voidvypis(strings)
{
// vypisna obrazovku
}
Pascal procedurevypis(s: string); begin
{vypisna obrazovku } end
Python defvypis(s):
#vypisna obrazovku
• Hodnotou(by value)
–Vytvoří se kopie hodnoty parametru a metodě se předá tato kopie
• Hodnotu původního parametru tedy metoda změnit nemůže (pracuje jen s kopií)
• Typické pro paměťově nenáročné datové typy (integer, float)
• Odkazem(by reference)
–Metodě se předá odkaz (reference, adresa) na hodnotu parametru
• Metoda tedy může hodnotu změnit a tím parametr použít jako výstupní
• Typické pro paměťově náročné datové typy (pole, string, objekt atd.) –nemusí se kopírovat velké množství dat
Předávání parametrů (ukázka)Jazyk
Volánífunkce
C++ voidfoo(int&x)
{
x = 5;
}
C# voidfoo(outintx)
{
x = 5;
}
intdnt= 1; foo(dnt);
// nyní má dnthodnotu 5
intdnt= 1; foo(outdnt);
// nyní má dnthodnotu 5
Návrh metody (chyby 1)
Co je špatně?
Nicneříkající název funkce i proměnných, chybí komentář spopisem není moc jasné, co funkce dělá a co se ve funkci děje Návrh metody (chyby 2)
Co je špatně?
Pro vstupy i výstupy jsou použity globální proměnné při volání funkce není vidět, co vše funkce mění (vedlejší efekty); lepší je pro vstupy použít parametry a pro výstupy návratovou hodnotu
Návrh metody (chyby 3)
V pořádku
Návrh metody (chyby 4)
Kratší, ale méně přehledný zápis. Někteří programátoři argumentují, že tato verze bude rychlejší, ale nárůst rychlosti by ve většině případů byl nicotný a často vůbec žádný (optimalizaci dnes umí provést i kompilátor). Určitě doporučuji použít předchozí verzi, je srozumitelnější a lépe se ladí (můžu si výpočet lépe odkrokovat).
• Pro opakované použití s různými daty
• Ověřit platnost vstupů
• Ne moc dlouhá
• Ne moc parametrů
• Vhodná jména: metody, parametrů, konstant
• Vstupy: použít parametry
• Výstupy: použít návratovou hodnotu –Nebo výstupní parametry
• Komentáře: metoda i programátorské obraty
• Vhodné formátování kódu
• Přehlednost, lepší orientace v kódu
–Místo jednoho dlouhého seznamu příkazů mám příkazy rozdělené do pojmenovaných logických bloků
• Rozdělení práce
–Jeden velký problém rozdělím na řadu menších (jednodušších) podproblémů
• Snazší zvládnout (po částech)
• Lze rozdělit mezi různé programátory
• Znovupoužitelnost kódu
–Volání metody s různými parametry
• Ušetří opakované psaní stejného (podobného) kódu
• Snazší testování kódu (i krokování)
• Snazší změna kódu (oprava chyby): jen na jednom místě
• Výhody oproti nestrukturovanému:
–Přehlednost, lepší orientace v kódu
–Rozdělení práce
–Znovupoužitelnost kódu
• Nevýhody oproti nestrukturovanému:
–Žádné
• Leda tak režie při předávání parametrů metodám (zejména při předávání hodnotou –kopírování dat)
• Použití:
–Jedno z nejběžnějších programovacích paradigmat
• Nicméně vhodnější je spíše pro programy menšího rozsahu (uvětšího rozsahu už se projevují výhody objektově
orientovaného programování)
• Co OOP je?
–Programovací styl, filozofie, technologie
• Co OOP není?
–Není řešením všech programátorských problémů
–Není ve všech případech lepší než jiné techniky
• Čím dál větší závislost na počítačích
–Tedy inasoftware
–Velké množství chyb
–Náročné spravovat
–Náročné rozšiřovat
–Velké náklady
–Mnoho chyb
• Inspirace: Stavebnictví
–Všechny domy využívají stejné cihly, tvárnice, šroubky, hřebíky, …
• Cíl: Vytvořit komponenty:
–Snadno pochopitelné a použitelné
–Znovupoužitelné pro různé případy
• Komponenty = základní stavební bloky
–Psát jen kód specifický pro danou aplikaci
• Levnější a rychlejší vývoj
–Méně psaní kódu, testování, psaní dokumentace
• Méně chyb v kódu
–Komponenta je využívána mnoha lidmi (a různými způsoby) odhalení „provozních“ chyb
• Programátoři nemusí být experti na vše
–Lze využít už existující komponentu
• Větší motivace pro programátory (někdy)
–Bude to používat více lidí programátoři více přemýšlejí nad návrhem komponenty (odpovědnost nebo ať si neudělají
ostudu)
• Sdílená nebo rovnou globální data
–V reálných (větších) programech jsou potřeba
–Ale tím je narušena modularita (nezávislost metod) nepřehlednost, chyby
• Náročné přizpůsobení programu změnám
–Není žádný mechanismus, který by provádění změn usnadnil
• I menší změna často způsobí změny kódu na mnoha různých místech
–Nejdříve drobné úpravy, později„hacky“ nepřehlednost, nestabilita Problémy a omezení strukturovaného programování II
• Složitější datové struktury (zásobník, strom, …)
–Problémy s přístupem
• Nelze nijak chránit dílčí datové položky (prvky), cizí programátor může celou strukturu „rozbořit“ (např. omylem přiřadí hodnotu NULL tam, kam nemá)
• Přístup k datovým položkám není jednotný –někdy to lze přímo, někdy pomocí funkcí, někdy kombinace –Problémy s různými datovými typy ve struktuře
• Např. zásobník je principiálně jedna struktura, ale kvůli kontrole datových typů musím mít „zásobník pro int“, „zásobník pro double“, „zásobník pro string“ atd. (a k tomu vždy řadu funkcí –lišící se jen typem –pro manipulaci se zásobníkem); a kdybych chtěl zásobník pro nový datový typ, tak si tohle vše musím zkopírovat a upravit (úmorné)
• Posílání zpráv (messagepassing)
–Jednotný způsob, jak přistupovat kobjektům (a tak číst nebo měnit jejich stav)
• Zapouzdření(encapsulation)
–Možnost skrytí datových položek a „pomocných“ funkcí přehlednější, bezpečnější
• Dědičnost(inheritance)
–Znovupoužitelnost (otestovaného, zdokumentovaného) kódu, a přitom snadná rozšiřitelnost/úpravy
• Polymorfismus(polymorphism)
–Umožňuje např. datové struktury pro libovolné typy
• Objekt(instance třídy)
• Třída
–Atribut
–Metoda
• Statickámetoda
Objekt, třída, zpráva
• Obecný (metodický) pohled:
–Entita reálného světa –objekt
–Šablona (vzor) pro objekty –třída
–Způsob komunikace objektů –zprávy
• Techničtější pohled:
–Třída= „lepší“ datový typ
• Definuje datové položky a možné operace s nimi
• Lepší proto, že umožňuje dědičnost (a související principy)
–Objekt= proměnná tohoto typu
–Reakce na zprávu= volání metody
Objekt (object)
Vlevo je objekt třídy Osoba –jmenuje se Jean Smith(ová), věk 35 let, váha 120 (liber = 55 kg). Má auto, což je další objekt: (vpravo) Objekt třídy Auto –jde o model Ford Escort, SPZ je THX-1138, barva bílá, najeto 64000 mil.
„Slupka“ objektu (obdélníkové bloky okolo dat objektu) znázorňuje zapouzdření –kdatům uvnitř (k„jádru“ objektu) se dá dostat jen spomocí metod, které tvoří tuto „slupku“.
Třída, instance třídy
Třída, instance třídy
Vlevo je vzor (šablona) pro auta, tj. třída Auto (classCar). Definuje, jaké datové položky všechna auta budou mít (výrobce, model, SPZ, barva, ujeté míle), a také chování všech aut (metody tvořící „slupku“).
Vpravo jsou dva objekty třídy Auto –liší se hodnotami datových položek. Chování ale budou mít všechna auta stejné (je dáno třídou). Objektům se někdy říká „instance třídy“.
Obrázek třídy připomíná papír, na kterém je nakreslený určitý tvar a jeho rozměry. Tím je znázorněno, že třída je šablonou
(vzorem) pro objekty.
• Každá třída definuje dvě věci:
–Atributy(attributes) = datové položky charakterizující stavobjektů
• Např. u třídy Auto: výrobce, model, SPZ, barva, …
• Říká se jim také proměnné instance (instance variables), členské proměnné (membervariables), fieldsnebo properties*
–Metody(methods) = funkce (procedury) charakterizující chováníobjektů
• Např. u třídy Auto: nastartuj, rozjeď se, zrychli, zastav, …
• Říká se jim také functionmembers
* Ale pozor, např. v jazyce C# pojem fieldznačí atribut, propertyje něco jako „lepší atribut“(viz závěr prezentace) a
attributesjsou úplně speciální prvky jazyka. Holt každý jazyk používá trochu jinou terminologii Definice třídy (ukázka, C#)
Situace: máme definovanou třídu Autoa chceme vytvořit nějaký objekt z ní (tj. instanci třídy Auto). Jazyk Kód Poznámka
C++ (objekt) Auto x; Automatické vytvoření objektu při deklaraci proměnné
C++ (ukazatel na objekt) Auto *p;
p = newAuto();
Java, C# Autox;
x = newAuto();
Ruční vytvoření objektu pomocí operátoru new
Objekty v Javě/C# se chovajípodobně jako
ukazatele na objekty v C++
• Zpráva = požadavek, aby objekt něco vykonal
–Např. provedl akci, vrátil hodnotu, …
–Metoda třídy = obsluha dané zprávy
• Chci-li poslat nějakou zprávu, musím určit:
–Kterému objektu zprávu posílám (příjemce)
–Jakou zprávu posílám (a s jakými parametry)
Situace: máme objekt x(příjemce) z třídy Auto, kterému chceme poslat zprávu Zrychli(s číselným parametrem 10).
Jazyk | Kód | Poznámka |
C++, Java, C# | x.Zrychli(10); | Operátor .(tečka), zápisodpovídá klasickému volání metody |
C++(když xje ukazatel) | x->Zrychli(10); | Operátor->(šipka), zápisodpovídá klasickému volání metody |
Objective-C | [x Zrychli:10] | Jiný způsobzápisu, ale význam je stejný (objektu xse pošle zpráva Zrychlisparametem10) |
Pozor: Poslat určitou zprávu lze objektu jen tehdy, když autor třídy příslušnou metodu označil jako veřejnou(veřejně použitelnou), viz dále.
Přístup k atributům (ukázka, C#)
Použijeme operátor .(tečka):
Pozor: Přistupovat k atributu objektu lze z kódu mimo třídu jen tehdy, když autor třídy příslušný atribut označil jako
veřejný(veřejně použitelný), viz dále.
Jako příjemce zprávy použijeme this:
Nebo jako by šlo o lokální proměnnou:
• Autor třídy může určit, které položky (datové i funkční, tj. metody) jsou veřejné, a které naopak neveřejné (např. jen pro použití uvnitř třídy jako pomocná proměnná či funkce)
C++, C# publicintx; privateintx; Neveřejná (jen uvnitř třídy)
Java publicintx; privateintx; Neveřejná(jen uvnitř balíčku*)
Objective-C @public intx; charc;
@private intx; charc;
Neveřejná (jen uvnitř třídy)
• Nyní rozlišujeme třídy a objekty
• Co kdybychom se ale na třídu také dívali jako kdyby to byl jeden (speciální) objekt?
–Pak bychom mohli mluvit o tom, že posíláme zprávu nějaké třídě (voláme metodu třídy)
• Taková metoda samozřejmě nemůže pracovat s hodnotami atributů (číst/měnit), protože třída atributy jen deklaruje,
neukládá si jejich hodnoty
–Jinými slovy taková metoda není závislá na konkrétním objektu
• Taková metoda se označuje jako statická metoda(též metoda třídy, static method, classmethod)
Statická metoda (ukázka, C#)
Metoda LatinskeJmenoje označena jako static, tedy nezávisí na atributech třídy Clovek(jméno, věk, váha, …)
Statická proměnná, statická třída
• Statická proměnná (proměnná třídy):
Statická metoda může používat pouze:
–Statické proměnné
–Statické metody téže třídy
• Příklady statických tříd (C#):
Klikni na název třídy azobrazí se související dokumentace na webu.
Konstruktor (constructor, ctor)
• Speciální metoda třídy, která vytvoří nový objekt (instanci) dané třídy
–Přesněji řečeno alokaci (zabrání) paměti pro atributy a uložení informace o tom, ke které třídě objekt patří (aby se vědělo, které metody lze použít) provede obvykle daný programovací jazyk
–Kód konstruktoru typicky provádí inicializaci objektu
• Nastavuje počáteční hodnoty atributů
• Provádí nějaké počáteční akce, které závisí na typu objektu (např. alokace paměti pro určitou datovou strukturu, otevření určitého souboru, připojení k databázi a výběr určité tabulky atd.)
• Pro jednu třídu může existovat více konstruktorů
–Odliší se parametry (C#, Java, PHP, …) nebo jménem (Perl) Konstruktor s parametry (ukázka, C#)
V řadě jazyků se konstruktor pozná tak, že je to metoda, která se jmenuje stejně jako třída (tj. v ukázce Clovek).
Vytvoření objektu (použití příslušného konstruktoru)
Destruktor (destructor, dtor)
• Speciální metoda třídy, která je provedena (těsně) před zánikem objektu
–Umožňuje provést „úklid“ (zavření otevřených souborů, uvolnění přidělené paměti atd.)
• Destruktor v C#:
–Jmenuje se stejně jako třída, ale na začátku názvu má vlnovku: ~Clovek
–Volá se automaticky (nelze explicitně zavolat)
• Lze tedy definovat jen jeden destruktor, a to bez parametrů
• Způsob automatické správy paměti
–Garbage(odpadek) = paměť obsazená objekty, které se už dále v programu nepoužívají
–Garbagecollector(sběrač odpadků) = nástroj, který tyto nepoužívané objekty detekuje (zjišťuje) a následně příslušnou paměť uvolňuje
• Detekce není úplně triviální, protože objekty můžou navzájem odkazovat na sebe a v případě cyklických odkazů tak může vzniknout falešný dojem, že jsou používány
–První použití: 1959 (jazyk Lisp)
C++ (objekt) Auto x;
…
(žádnáakce)
C++ (ukazatel na objekt) Auto *p;
p = newAuto();
…
deletep;
Java, C# Autox;
x = newAuto();
…
(žádná akce)
Automatické zrušení objektu na konciplatnosti proměnné
Ruční zrušeníobjektu pomocíoperátoru delete
Automatické zrušení objektu, když už se nepoužívá (díky
garbagecollectoru)
• Mám objekt třídy Button(tlačítko v GUI) a ten má atribut Text
–Pro přístup k atributu musím (kvůli zapouzdření) použít příslušné metody:
–Přitom hezké by bylo moci psát (jako by to byl publicatribut):
–Toto lze zařídit v jazyce C# pomocí tzv. property
Propertynení proměnná (nemá vyhrazené místo v paměti), je to spíše sada metod. Tyto metody se zavolají při přístupu k dané property(metoda getpři čtení, metoda setpři zápisu –zapisovaná hodnota je uložena ve speciální proměnné value).
Pokud je tělo daných metod triviální (jako v ukázce výše), lze použít i zkrácený zápis (vlevo). Místo pro uložení hodnoty si C# vytvoří automaticky sám.
Dědičnost (inheritance)
• Výhoda: znovupoužitelnost
–Využít už existující kód (třídy)
• Popsat jen změny:
–Přidat
–Změnit (přepsat)
–Odebrat* Jednoduchá dědičnost
Jednoduchá dědičnost
Předci jsou obecnější, potomci jsou konkrétnější: Osoba je konkrétnější typ Objektu, Doktor je konkrétnější typ Osoby, Psychiatr je konkrétnější typ Doktora.
Zde zobrazená dědičnost je jednoduchá vtom smyslu, že každá třída má nejvýše jednoho předka.
Třída Object(Objekt) je předkem všech ostatních tříd. Třída Person(Osoba) přidává tři nové atributy: jméno (name), věk (age) a váhu (weight). Třída Doctor(Doktor) je potomek třídy Person: dědí všechny tři atributy od třídy Persona navíc přidává dva nové: škola (medSchool) a číslo licence (licenseNo). Jiný potomek třídy Personje Typist(Písař), který přidává jen jeden atribut: počet slov za minutu (wpm). Třída Psychiatrist(Psychiatr) je potomkem třídy Doctor.
Jednoduchá dědičnost
Jednoduchá dědičnost
Instance (objekt) třídy Doctormá všechny atributy definované u třídy Doctor(school, license) i u všech jejích předků, tj. zde atributy třídy Person(name, age, weight) i třídy Object(bez atributů).
Totéž platí i pro metody: u objektu třídy Doctorlze používat metody definované u třídy Doctori u všech jejích předků, tj. zde
metody setWeight, getWeighta examine(na obrázku to však znázorněno není)
Vícenásobná dědičnost
Instance (objekt) třídy NavyDoctormá všechny atributy definované všemi svými předky, tj. name, age, weight(od třídy
Person), school, license(od třídy Doctor) i ranka ship(od třídy NavyOfficer)
Třída NavyOfficer(Námořní důstojník) je potomkem třídy Persona definuje dva nové atributy, rank(hodnost) a ship(loď), a dvě nové metody, hoistTheMainsail(Napnout hlavní plachtu) a swabTheDeck(vytřít palubu).
Třída NavyDoctor(Doktor námořník) je potomkem jak třídy Doctor, tak třídy NavyOfficer, zdědí tedy atributy a metody obou tříd.
Situace: Chci vytvořit třídu Doctor, která je potomkem třídy Person.
Jazyk C++, C# | Kód classDoctor: Person { // popis změn } | Poznámka |
Java | classDoctorextendsPerson { // popis změn } |
|
C++ | class NavyDoctor: Doctor, NavyOfficer { // popis změn } | C++ umí vícenásobnou dědičnost |
Přiřazení potomek ↔ předek Osoba o = newOsoba(); Doktord = new Doktor();
// Doktorje pomotekodOsoba Osobao2 = d; // lzeprovést? Doktord2 = o; // lzeprovést?
Jinými slovy: Lze se k Doktorovi chovat tak, jako by byl Osobou? Jinými slovy: Lze se k Osobě chovat tak, jako by byla Doktorem? Přiřazení potomek předek
Jméno Osoba
Věk Jméno
Váha Věk
ČísloOsvědčení Váha
řekniVáhu() ČísloOsvědčení
nastavVáhu() řekniVáhu()
vyšetřiPacienta() nastavVáhu()
vyšetřiPacienta()
Přiřazení potomka (Doktor) do předka (Osoba) je vždy bez problémů, jednoduše se některé informace „zapomenou“. Ostatně každý Doktor je díky dědičnosti Osobou (umí vše co Osoba), takže s ním lze jednat jako s Osobou.
Osoba Doktor
Jméno Jméno
Věk Věk
Váha Váha
řekniVáhu() ČísloOsvědčení???
nastavVáhu() řekniVáhu()
nastavVáhu()
Přiřazení předka (Osoba) do potomka (Doktor) je obecně problematické, protože předek nemusí umět vše, co se od potomka žádá. Kdybych se Osoby, která má být považována za Doktora, zeptal na číslo osvědčení, co mi má odpovědět? Žádný takový atribut nemá. Kdybych ji požádal o vyšetření pacienta, co má udělat? Žádnou takovou metodu nemá.
Osobao2 = d;
Lze vždy provést (nejen při přiřazování, ale i v rámci předávání parametrů metodám atd.)
Doktord2 = o;
Problematické, takže v jazyce C# implicitně provést nelze. Programátor ale může konverzi vynutit explicitním zápisem:
Doktord2 = (Doktor)o;
Proměnná ose přetypuje (zkonvertuje, anglicky cast) na třídu Doktora teprve pak je přiřazena do proměnné d2. Odpovědnost za logickou správnost konverze je na programátorovi (a hlavně je přímo v kódu vidět, že k takové konverzi dochází.
• Obvykle je dědění možnost, jak něco udělat
–Můžou ale existovat situace, kdy programátor potřebuje dědění
vynutit, nebo naopak zakázat
• Zákaz dědění od nějaké třídy:
–Modifikátor třídy: final(Java), sealed(C#)
• Vynucení dědění:
–Tzv. abstraktní třídy
• Abstraktní metoda:
–Před deklaraci metody se napíše abstract(C#, Java)
–Není definováno tělo metody
• Aby bylo možné danou metodu někdy zavolat, je třeba definovat její tělo v některém potomkovi dané třídy
• Abstraktní třída:
–Před deklaraci metody se napíše abstract(C#, Java)
• Má-li třída alespoň jednu abstraktní metodu, pak musí být sama označena jako abstrakt
–Nelze vytvářet instance třídy(!)
•
Třída slouží jen k tomu, aby se od ní dalo dědit –aby sloužila jako předek nějakých dalších tříd (viz dále polymorfismus: pozdní vazba) Abstraktní metody/třídy
Třídy s názvem kurzívou jsou abstraktní třídy: Shape(Tvar), Polygon(Mnohoúhelník). Třídy s tučným názvem označují konkrétní (ne- abstraktní) třídy: RegularPolygon (Pravidelný mnohoúhelník), IrregularPolygon (Nepravidelný mnohoúhelník), Rect(Obdélník), RoundRect(Obdélník s kulatými rohy), Circle(Kruh).
Od abstraktních tříd zde nemá ani smysl vytvářet instance, protože tyto třídy neobsahují informace (atributy) potřebné pro vykreslení příslušného geometrického tvaru. Konkrétní třídy už tyto informace
obsahují, např. Circlemá center(střed) a radius(poloměr), takže daný kruh by vykreslit šel. Abstraktní třídy tedy zde fungují jen jako pomůcka –společný předek určité skupiny tříd.
Výhody Nevýhody
Znovupoužitelnostkódu Vyžaduje OOP
Změny bez zásahůdo původního funkčního a otestovaného kódu
Podporuje tvoru rozšířením či upřesněním již existujícího, nekompletním předěláním Možné snížení výkonu (trochu)**
Dědění vlastností,které nejsou žádoucí
Obtížné ladění programu přivětším množství tříd*
Zapouzdření (encapsulation)
• Závislostcizího kódu na konkrétní implementaci mého modulu (mé třídy) problémy
–Změním implementaci (vylepšení, oprava chyby) cizí kód může přestat fungovat
–Cizí kód mi může „rozbořit“ datové struktury
–Jen doporučení (např. v dokumentaci) nestačí
–Je nutné omezit/řídit možnosti přístupu
• Přístupnost (C#):
–private= jen třída (jen metody dané třídy)
–protected= jen třída a potomci
–public= veřejné (kdokoli)
Zapouzdření (příklad)
• Osoba.Zisk():
return příjmy –výdaje;
• Osoba.Zisk():
return příjmy –výdaje+ úspory * úrokováMíra–daně(příjmy, odpočitatelné položky); Lze změnit implementaci metody, navenek se nepozná
Zapouzdření
Uživatel serychle naučí s třídou pracovat (nemusí se zabývat detaily)
Znovupoužitelné třídy je třeba opatrně naplánovat (zejménaveřejná rozhraní)
Uživatel nemusí mít strach,že něco pokazí Přístup přes metody může být (trochu)
pomalejšínež přímý přístup
Tvůrce může změnit implementaci, ale navenek se
nic nezmění –vše funguje
• „Vícetvarost“
• Týká se třech oblastí:
–Dle parametrů
• Tzv. šablony (templates) –nechme nyní stranou
–Přetěžování (overloading) metod / operátorů
• Pod jedním názvem je více metod / operátorů (rozlišují se typem parametrů)
–Pozdní vazba
• Jedna proměnná může obsahovat více různých typů objektů (ale jen potomci) Přetěžování metod (příklad)
Přetěžování operátorů (příklad)
// Matice M krát vektor x je vektor y
y = M * x;
// Matice M krát číslo 2 je matice N N = M * 2;
// Číslo 4 krát vektor x je vektor y
y = 4 * x;
V principu je to totéž jako přetěžování metod, protože výše uvedené příklady jdou přepsat jako: y = operátor_krát(M, x);
N = operátor_krát(M, 2); y = operátor_krát(4, x);
Přetěžování metod a operátorů
Jednodušší (pro uživatele)rozhraní tříd a knihoven Přivýběru názvů metod a parametrů musí být tvůrce
opatrný
Přehlednějšíkód při používání takových metod a operátorů
• Týká se volání metod třídy
• Časná vazba(static binding, early binding)
Jsou-li názvy zvoleny špatně, může být uživatel zmaten
–Typ objektu je určenuž při kompilaci (podle typu příslušné proměnné)
• Pozdní vazba(latebinding, dynamic binding, dynamic dispatch)
–Typ objektu je určen až při běhu programu (objekty si svůj typ „pamatují“)
• Proměnná je oficiálně typu (třídy) XYZ
• Do ní lze přiřadit i jakéhokoli potomka třídy XYZ (přiřazení potomek předek je vždy v pořádku)
• Až při běhu programu se zjistí, která třída je v dané proměnná skutečně uložena a zavolá se příslušná metoda (tj. metoda
potomka XYZ, ne metoda XYZ)
• Chci mít datovou strukturu (např. pole), ve které budou prvky různého typu. S těmito prvky chci provádět nějakou operaci (např. print). Jak to provést?
• Řešení bez využití dědičnosti (časná vazba):
–Každý prvek si bude pamatovat svůj typ (ve vhodné datové položce)
–Pro každý typ vytvořím „konverzní“ funkci, která prvek převede na daný typ
–U každého typu udělám funkci (metodu) print
–Při procházení pole nejprve z datové položky zjistím, jakého typu položka je, pak ji konverzní funkcí formálně převedu na daný typ a nakonec zavolám print
Časná vazba
For(inti = 0; i < pole.velikost; i++)
{
Objectprvek= pole[i];
if (prvek.typ == INT_OBJECT) PrevedNaINT_OBJ(prvek).print();
else if (prvek.typ == STRING_OBJECT) PrevedNaSTRING_OBJ(prvek).print(); else if (prvek.typ == CIRCLE_OBJECT) PrevedNaCIRCLE_OBJ(prvek).print(); else if (…)
PrevedNa…
}
Nevýhody tohoto řešení:
1) Pracné, složité, nepřehledné
2) Při přidání nového typu musím změnit i veškerý kód, který by daný typ používal (musím přidat nový if). Ale ten kód nemusí být můj kód…
Při použití pozdní vazby stačí mít společného předka (např. třídu Object) a na něm mít deklarovanou metodu print()(klidně bez těla, tj. abstraktní). U potomků (u tříd Int_Obj, String_Obj, Circle_Obj, …) tělo metody print()definuji.
For(inti = 0; i < pole.velikost; i++)
{
Objectprvek = pole[i]; prvek.print();
}
Použije se vždy taková metoda print(), která odpovídá danému typu (dané třídě, která musí být potomek třídy Objekt). Navíc při přidání nového typu stačí u dané třídy nadefinovat tělo metody print()a nic dalšího (ani výše uvedený kód) neměním.
Pozdní vazba (ukázka)
Situace: Chci zařídit, aby se metoda print()volala pomocí pozdní vazby.
C# classObject{ virtualpublic print();
}
classInt_Obj{ overridepublic print();
}
C++ classObject{ virtualpublic print();
}
classInt_Obj{ public print();
Daná metoda se pak označuje jako „virtuální“.
Daná metoda se pak označuje jako „virtuální“.
}
Java classObject{ public print();
}
classInt_Obj{ public print();
}
Výhody OOP
U metodje pozdní vazba výchozíchování (není třeba přidávat žádný modifikátor).
Minimalizace opakování kódu (dědičnost) –Není nutné psát, testovat, spravovat
• Skrytí implementačních detailů (zapouzdření) –Bezpečnější, jednodušší na pochopení
• Uživatel třídy si nemusí tolik pamatovat (polymorfismus)
• Není nutné přepisovat kód jen proto, že někdo přidá nový typ (pozdní vazba)
Snazší vytvořit a používat (znovupoužitelné) SW komponenty
Dědičnost, nebo asociace?
• Vztah „je“ („is“) dědičnost tříd
–Např. „Doktor je Osoba“ (je osobou –má všechny její vlastnosti)
• Vztah „má části“, „obsahuje“ („has“) nebo „komunikuje s“ asociace tříd
–Např. „Telefon má Reproduktor a Mikrofon“ (má části, skládá se z)
–Jak zachytit (implementovat) asociaci, to si ukážeme dále
(mezi dvěma třídami)
• Obě třídy
–Vhodné v situaci, kdy třídy navzájem intenzivně komunikují (tj. musí vědět jedna o druhé a navzájem si volají metody)
• Jedna třída
–Vhodné pro agregaci/kompozici (jedna třída je částí druhé)
• Ani jedna z nich
–Vhodné pro situaci, kdy je asociace složitá –realizaci asociace zastane samostatná (třetí) třída
Např. Zaměstnanec (Employee) a Manažer (Manager) –oba musí komunikovat navzájem (manažer posílá úkoly zaměstnanci, zaměstnanec se ale také často obrací na svého manažera). Realizace: třída Employeemá atribut manager(kdo je jeho manažerem), třída Managermá jako atribut underlings(podřízení). Tedy existence vztahu je vidět v obou třídách (v obou třídách je nový atribut).
Implementace asociace: jedna tříd classŠkola {
stringnázev;
Katedra[] katedry;
// další položky
}
classKatedra { stringnázev; Osoba vedoucí;
// další položky
}
Např. škola a její katedry (katedra informatiky, katedra jazyků, katedra práva atd.). Vztah lze jednoduše implementovat jako nový atribut ve třídě Škola –seznam kateder. Ve třídě Katedra se nic měnit nemusí.
Implementace asociace: ani jedna
Např. vztah „sdílí kancelář“ (zaměstnanci). To by šlo udělat tak, že by každý zaměstnanec měl seznam kolegů, kteří sním sdílí kancelář, ale tyto seznamy by se pracně musely udržovat a synchronizovat. Jednodušší je vytvořit novou třídu Kancelář (Office) a ta by u sebe měla (jako atribut) seznam obyvatel (occupants). Tato třída tedy zachycuje (implementuje) daný vztah. V ukázce je ještě pohodlnější varianta –i zaměstnanec má informaci o tom, v jaké je kanceláři (atribut office).
• Někdy se rozlišuje míra těsnosti vztahu tříd, kde jedna obsahuje druhou
–Když zanikne „celek“, zaniknou i „části“?
• Kompozice (těsnější vztah):
–Např. vztah Škola –Katedry (vše myšleno jen jako organizační jednotky)
• Zanikne-li Škola, pak zaniknou i Katedry (Katedra nemůže samostatně existovat)
• Agregace (volnější vztah):
–Např. vztah Katedra –Vyučující
• Zanikne-li Katedra, Vyučující žijí dál (samostatně existují)
• Úkol abstrakce: reálný svět třídy
–Listy (v hierarchii dědičnosti) jsou obvykle snadné, protože ty odpovídají typům objektů z reálného světa
–Problém bývá vymyslet dobře tu hierarchii
• Vznikají tak další, pomocné třídy
–A také je třeba vymyslet, které atributy a metody budou u kterých tříd
1. Mám nějaké třídy
2. Najít společné atributy nebo chování dvou nebo více tříd
3. Tyto společné věci vyčlenit do nové (pomocné) třídy
4. Ostatní zmíněné třídy od této nové třídy budou dědit (a definují jen odlišnosti)
Postup lze opakovat
• Přístupy k abstrakci:
–Dle funkce (tj. dle metod tříd)
–Dle struktury (tj. dle atributů tříd)
–Dle obojího
–Minimální návrh
• Příklad:
–Rovinný obrazec (Shape), Čtverec (Square), Obdélník (Rectangle)
•
Potřebuji znát umístění a rozměry obrazce a mít metodu pro počítání plochy (area) obrazce Abstrakce dle funkce
• Zaměření na funkce (metody objektů)
• Lze napsat metodu area()tak, aby se dala použít u obou tříd?
–Tj. byla jen jedna metoda?
–Ano
–Čtverec je pak jen speciální případ Obdélníku
Čtverec ale zdědí 4 atributy, stačily by mu přitom jen 3 (top, left, side)
Zaměření na efektivní uložení dat (strukturu)
• Čtverci stačí tři atributy, obdélník si přidá čtvrtý
–Datově lépe už to nejde
–Obdélník je zde „obohacením“ (rozšířením) čtverce
Ne moc logické, hierarchie se navíc odvozuje od interních detailů (datových struktur), tj. při změně implementace objektů bude hierarchie špatně.
Abstrakce dle obojího
Hledáme, co mají třídy společného (obecně)
–Čtverec i obdélník mají společný obecný vzorec:obsah = šířka ∙ výška
–Ale datové struktury mají jiné dát je až do potomků
• Předek konkrétní hodnoty získá metodami
Náročné navrhnout, mnoho abstraktních tříd může znamenat pomalost a nepřehlednost
Minimální návrh
Minimalizovat počet úrovní a také počet tříd
–Jeden společný předek se hodí (polymorfismus) Nevyužije v plné šíři výhod dědičnosti, ne moc logické Plusy a minusy
Funkce Odpovídá reálnému světu, funkční soudržnost,
snadno rozšiřitelné
Strukturanení optimální (zbytečná duplikace)
Struktura Efektivní uloženídat Neintuitivní, závislost na implementaci, nepřizpůsobitelné
Obojí Intuitivnía datově efektivní Náročnéna návrh, může klesnout výkon (hodně abstraktních tříd)
Minimální počet úrovní Méně tříd –přehlednější, jednodušší debugging Nezachová vztahyreálného světa, nevyužije plně
dědičnosti (redundance kódu)
• Záleží na prioritách(co je hlavní):
–Přehlednost, intuitivnost dle funkce
–Efektivita uložení dat dle struktury
• Při velkých datových objemech nebo při velkém množství objektů daného typu
–Obě předchozí kritéria kombinace
–Jednoduchost, výkon minimální návrh
Silné propojení tříd(strong/high/tightcoupling)
• O silné propojení jde, když:
–Je vzájemná závislost na vnitřních strukturách
–Třídy si posílají mnoho různých zpráv nebo jsou zprávy „složité“ (záleží na pořadí nebo mají hodně parametrů)
• Silné propojení vadí,protože brání změnám
–Nelze změnit jednu třídu,protože to „rozbije“ tudruhou (třídy se navzájem„drží pod krkem“)
Zmenšení propojení: zprávy
Je to silné propojení? Ano: je zde hodně různých zpráv, záleží na pořadí.
Proč je to špatně? Třídu Autokvůli tomu nelze změnit, např. těžko by se dělalo auto s automatickou převodovkou (bez spojky
atd.).
Jak to udělat lépe? Třída Autoať má jedinou metodu nastartuj(klíč)a ať si sama interně zařídí to nastartování. Zmenšení propojení: struktura
Je to silné propojení? Ano: třída Doktor šahá na vnitřní strukturu (jméno, příjmení) jiné třídy (Osoba).
Proč je to špatně? Třídu Osobakvůli tomu nelze změnit, např. těžko by se dělala osoba s prostředním jménem (např. „William Henry Gates“).
Jak to udělat lépe? Doktor by měl využít metodu getJmenosvého předka, tj. return "MUDr. " + base.getJmeno();
Pravidlo nezávislosti(LawofDemeter)
Pravidlo, které předchází závislosti na struktuře cizích tříd
• Říká: třída by měla znát (a využívat) jen své „přímé okolí“, nikoli vzdálenější třídy
Alternativní znění: při volání metody je povolena jen „jedna tečka“. Tedy volání x.metoda()je povoleno, ale x.y.metoda()už nikoli, protože to už vyžaduje znalost vnitřní struktury objektu x(že má nějakou položku y).
Příklad: viz cvičení (Psí nohy a Zákazník a peněženka).
Pravidlo nezávislosti(LawofDemeter)
• Technická definice pravidla:
–Když mám objekt X s metodou M, tak metoda M může volat pouze metody následujících objektů:
• X (objektu samotného, tj. this)
• Přímá součást X (atribut)
• Parametr metody M
• Lokální proměnná (objekt vzniklý uvnitř metody M)
• Globální proměnná
Např. pokud jako parametr dostanu objekt třídy Škola, neměl bych volat metodu Škola.katedra[INF].setVedoucí("Trčka"), protože tím nevolám metodu parametru (školy), ale jeho součásti. Měl bych volat pouze některou z metod školy jako celku, protože jinak budu závislý na vnitřní struktuře školy (že má katedry atd.).
Soudržnost (cohesion)
• Jak dobře atributy a metody třídy odpovídají dané myšlence (konceptu)
• Hodnotí se:
–Relevance (relevance)
–Potřebnost (necessity)
–Úplnost (completeness)
• Souvisí prvek s třídou přímo?
–Nebo prvek s třídou souvisí prostřednictvím „neviditelné“ jiné třídy?
Atributy značkaAutaa rokVýrobyAutaje lepší dát do samostatného objektu (Auto). Už jen proto, že osoba nemusí mít auto, nebo že může mít aut více. Pro porušení relevance je typické, že název atributu/metody obsahuje jméno jiného objektu (znackaAuta, rokVyrobyAuta).
• Je prvek nezbytně nutný?
Potřebujeme u zraněného pacienta znát oblíbenou TV show? To leda tak u pacienta, který už je v rekonvalescenci…
• Pokrývá vše potřebné?
U zásobníku by kromě metody push(přidej prvek na zásobník) měla být určitě metoda pop(vrať/odeber prvek zvrcholu zásobníku).
• Snažíme se o silnou funkční soudržnost…
–Každá metoda je relevantní, nezbytně nutná a dohromady metody pokrývají vše potřebné
• … i o silnou strukturální soudržnost
–Každý atribut je relevantní, nezbytně nutný a dohromady atributy pokrývají vše potřebné
• Patří mezi deklarativní paradigmata
–Důraz: coprogram počítá (vztah vstup–výstup)
–Ne tak důležité: jakprogram počítá (akce)
• Styl: práce s funkcemia jejich aplikace na argumenty
• Imperativní
–Program = příkaz
–Výpočet = posloupnost akcí (stav stav)
–Výsledek = účinek těchto akcí
–Jazyky: C, C++, C#, Java, Python, PHP, …
• Funkcionální
–Program = výraz
–Výpočet = úprava (zjednodušování) výrazu
–Výsledek = hodnota (dále nezjednodušitelný tvar výrazu)
–Jazyky: Lisp(1958*), Scheme(1975), Erlang(1986), Haskell(1990), Scala(2003), F# (2005), Clojure(2007), …
• Akademická sféra
• Komerční sféra:
–Jazyk Erlang(Ericson) –systémy odolné proti selhání (telekomunikace)
–Jazyk Scheme–simulace
–Jazyk OCaml–finanční analýza, verifikace ovladačů zařízení, programování průmyslových robotů
–Jazyk Haskell–letectví a kosmonautika, návrh hardware
1997 JavaScript Některé koncepty až později(např. 2008: closures)
2007/11 | C# 3.0 | Pěknýpřehledový článek: |
|
| POPOVIC, Jovan. Functionalprogrammingin C#. CodeProject[online]. 2012-06-10 [cit. 2014-04- |
|
| 25]. Dostupné na WWW: http://www.codeproject.com/Articles/375166/Functional- |
|
| programming-in-Csharp |
2009/06 | PHP 5.3 |
|
2011/08 | C++11 |
|
2014/03 | Java 8 | Některé koncepty už v Javě 7 (např. closures) |
Co jsou to closures(a další koncepty), to si samozřejmě ukážeme dále Zajímavé články
• Zajímavé články (anglicky), které přinášejí argumenty, proč „klasické“ imperativní (příkazové) programování nestačí (vždy):
–CARMACK, John. FunctionalProgrammingin C++. #AltDevBlog[online]. 2012-04-26 [cit. 2014-04-29].Dostupné na WWW:
http://www.altdevblogaday.com/2012/04/26/functional-programming-in-c/
•„No matter what language you work in, programming in a functional style provides benefits. You should do it whenever it is
convenient, and you should think hard about the decision when it isn’t convenient.“
–MILEWSKI, Bartosz. The Downfall of Imperative Programming. FP Complete[online]. 2012-04-09 [cit. 2014-04-29].Dostupné na WWW: https://www.fpcomplete.com/blog/2012/04/the-downfall-of-imperative-programming
•„If you think you can stay away from functional programming, you're mistaken.“
John Carmacje programátor, jeden ze zakladatelů id Software (vytvořili počítačové hry Wolfenstein3D, Doomnebo Quake). BartoszMilewskinapsal knihu o C++ a pomáhal při návrhu programovacího jazyka D.
• Deklarativnost
–Vyšší úroveň jazyka zápis je bližší specifikaci, krátký zápis (bez nepodstatných implementačních detailů), čitelný zápis
• Ortogonalita
–Se všemi hodnotami se pracuje stejným způsobem jednoduchá syntaxe i sémantika, velká expresivita (šíře myšlenek, které lze jazykem popsat)
• Bohatý typový systém, silná typová kontrola
–Rychlá detekce chyb, snadné ladění Referenční transparentnost
–Stejný výraz má vždy stejný výsledek (nezávisí na stavu programu, nemá vedlejší efekty)
• Proměnné nemění svou hodnotu (jen jedno přiřazení)
–Z ní vyplývající možnosti formální manipulace sprogramy, zejména:
• Dokazování správnosti
• Paralelizace výpočtů (bez strachu z chyb typu racecondition)
• Optimalizace kódu
–Výraz/funkce/jazyk s touto vlastností se označuje jako „pure“ (čistý)
Haskell
• Budeme si vše ukazovat na jazyku Haskell
–Patří mezi „čisté“ (pure) funkcionální jazyky
–Má jednodušší syntaxi než C#/Java/atd. na naučení se principů funkcionálního programování je vhodnější
• Zajímavé webové stránky:
• Interaktivní výuka základů jazyka (anglicky)
• Příručka pro začátečníky (česky)
–http://www.fi.muni.cz/~xukrop/ib015/
• Přehledný seznam zdrojů (slovensky Příklady programů
• Funkce mají ve funkcionálních jazycích silnou pozici –říká se, že funkce jsou v daném jazyce first-classcitizen(„občan první třídy/úrovně“)
–Tedy že s funkcemi lze provádět stejné operace jako sjinými datovými typy, například:
• Lze přiřadit funkci do proměnné
• Lze předat funkci jako parametr (do jiné funkce)
• Lze použít funkci jako návratovou hodnotu (z jiné funkce).
• Funkce vyššího řádu (highorderfunction) = funkce, která má jako parametr funkci nebo která vrací funkci
• Příklady typických funkcí vyššího řádu:
map Aplikuje danou funkci (parametr) na každý prvek seznamu
filter Použije danou funkci(parametr) jako kritérium výběru prvků ze
seznamu
fold „Sbalí“ (agreguje) prvky seznamu pomocí dané funkce (parametr)
Anonymní funkce
• Anonymní funkce (lambda function) = funkce, která má definované tělo a která je volaná, ale která nemá určené jméno (identifikátor)
–Např. funkce (\x -> x * x)je anonymní funkce
–Dokonce i (+1), (*3), (==20)jsou anonymní funkce, jak uvidíme dále (viz currying)
• Curryingje technika, kdy je funkce s více parametry převedena na „řetězové“ volání více funkcí, které mají jen jeden
parametr
–Hovoří se o tzv. částečné aplikaci funkce (partialfunctionapplication) nebo také o „zafixování“ některých parametrů funkce
• Jazyk Haskellpoužívá currying
• Všimněme si, že díky curryingujsou všechny funkce „svíce parametry“ vHaskelluautomaticky funkcemi vyššího řádu (protože mají formálně jen jeden parametr a tedy musí vracet funkci)
–Funkce +(plus) má jeden parametr (x) a vracífunkci(která svůj parametr zvětší o x)
–Funkce mapmá jeden parametr (funkci f) a vracífunkci(která seznam převede na jiný seznam aplikací funkce fna jednotlivé
prvky seznamu)
• Funkce map je tedy funkce „zobecni na seznam“, protože z funkce typu např. „číslo číslo“ udělá funkci typu „seznam čísel
Lexikální uzávěr
• Lexikální uzávěr(closure) = funkce společně s „prostředím“, ve kterém je tato funkce odkazovaná (definovaná)
•U definice soucet= \x -> (\y -> y + x)je funkce (\y -> y + x)lexikálním uzávěrem, protože tato (anonymní) funkce potřebuje vědět hodnotu x, která je ale definována mimo funkci –v tzv. prostředí (environment) této funkce
–Prostředím je zde myšlena funkce soucet(a xje v tomto prostředí definována jako parametr funkce soucet)
–Pro svou funkčnost (aby mohla vrátit správnou hodnotu) potřebuje funkce (\y -> y + x)vědět (zapamatovat si, uložit si), v jakém prostředí byla definována (odkázána), která proměnná je tím x, které sama pro výpočet potřebuje (např. uloží si adresu proměnné x)
–Lexikální uzávěr si tedy lze představit jako funkci s „neviditelnými“ parametry (zde je tím neviditelným parametrem proměnná x)
Líné vyhodnocování
• Líné vyhodnocování(lazyevaluation) je taková strategie při vyhodnocování výrazů, kdy výraz je vyhodnocen až v okamžiku, kdy je vyžádána jeho hodnota
• Příklad (jazyk C#):
U jazyka Haskellpodobný příklad použít nelze, protože Haskellumí dělit nulou (výsledkem je kladné konečno, které se vypíše
jako 1.#INF)
Výraz (x != 0)je vyhodnocen jako falsea protože výraz (false&& cokoliv)je vždy false(nezávisle na hodnotě výrazu cokoliv), tak se výraz ((1 / x) == 0)vůbec nevyhodnocuje a tedy nedojde k chybě dělení nulou při vyhodnocení podvýrazu (1 / x). Nekonečné datové struktury
• Jazyk Haskellpoužívá líné vyhodnocování
• Díky tomu lze pracovat i s (potenciálně) nekonečnými datovými strukturami
–Pokud stačí k vyhodnocení výrazu znát konečný počet prvků takové struktury, pak k žádnému nekonečnému zacyklení (při průchodu strukturou) nedojde
Nekonečné datové struktury (příklad)
• Nekonečnou strukturu lze zapsat třeba takto:
Vstup: [1..]
Výstup: [1,2,3,4,5,6,7,8,9,10,11,…
Funkce „výpis na obrazovku“ potřebuje postupně všechny prvky seznamu, takže výpis pokračuje jedno číslo za druhým až do doby, kdy dojde paměť nebo kdy uživatel ručně přeruší běh programu.
Máme-li ale definovanou funkci prvek, která vrací n-týprvek seznamu (viz cvičení), tak následující program bez problému skončí (chceme vypsat 5. prvek nekonečné struktury):
Vstup: prvek5[1..]
Výstup: 5
Funkce prvek„donutí“ jazyk Haskell, aby postupně zjistil prvních 5 prvků seznamu[1..], další prvky seznamu ale pro získání výsledku nutné nejsou, a tak se díky línému vyhodnocování ani nezjišťují.
Datový typ výrazu můžeme zjistit pomocí příkazu :t výraz
Výrazem může být samozřejmě i funkce (funkce &&je logické AND):
Typový systém: funkce
Zápis tvaru X -> Yznamená datový typ „funkce, která ztypu X(parametr) udělá typ Y(výsledek)“
• Zápisy s ->(šipkou) se závorkují zprava, tedy zápisBool-> Bool-> Boolve skutečnosti znamenáBool-> (Bool-> Bool)
–Tedy jde o funkci, která má parametr typu Boola vrací funkci (typu Bool-> Bool)
–Jde o další ukázku toho, že funkce v Haskellumají jen jeden parametr (a že funkce může vracet funkci)
• V jazycích, kde funkce mají více parametrů (např. C#), bychom to četli tak, že je to funkce, která má dva parametry Boola
vrací Bool
Typová třída (typeclass)
Numa(před =>) znamená, že datový typ aje z typové třídy Num
–Do typové třídy Numpatří datové typy Int, Float, Doublea řada dalších* číselných typů
–Funkce +(plus) tedy umí pracovat s různými číselnými typy
• Připomeňme, že zápis a -> a -> a znamená, že funkce +(plus) má parametr typu aavrací funkci (typu a -> a)
•
Existují i další typové třídy (např. Ord, seřaditelnétypy):
Odvození typu (type inference)
Zatím jsme se bez určování datových typů obešli, protože Haskellsi je odvodí sám:
--n-ty prvek seznamu (prvni = 1) prvek 1 (x:xs) = x
prvek n (x:xs) = prvek (n-1) xs
V definici funkce prvekHaskellvidí, že s prvním parametrem funkce děláme operaci (n-1), tedy že patří do typové třídy Num(to
vyplývá zdatového typu funkce -(minus)).
Druhý parametr má tvar (x:xs), tedy jde o seznam (výsledkem funkce :(dvojtečka) je seznam). Výsledkem funkce prvekje x,
což je prvek seznamu. Datový typ prvků seznamu může být libovolný, nemusí jít o typ a(proto je označen jako b).
Typová signatura (type signature)
Pomocí tzv. typové signatury si můžeme datový typ funkce určit (upřesnit) sami:
--n-ty prvek seznamu (prvni = 1)
prvek :: Int -> [b] ->b ß Typová signatura
prvek 1 (x:xs) = x
prvek n (x:xs) = prvek (n-1) xs
Typovou signaturou funkce jsme datový typ jejího prvního parametru omezili na Int(celé číslo), čímž jsme zakázali funkci volat s parametrem typu např. Floatnebo Double(což by stejně nedávalo smysl a jen by to vedlo kproblémům – neočekávanému chování funkce).
Typový systém podrobněji
• Podrobnější vysvětlení typového systému je například zde:
–Wikibookscontributors. Haskell/Type basics. Wikibooks, The Free Textbook Project[online].2014-05-09, 02:27 UTC [cit. 2014-05-18]. http://en.wikibooks.org/w/index.php?title=Haskell/Type_basics&oldid=2650061
–Wikibookscontributors. Haskell/Type basicsII. Wikibooks, The Free Textbook Project[online].2014-04-24, 08:16 UTC [cit. 2014-05-18]. http://en.wikibooks.org/w/index.php?title=Haskell/Type_basics_II&oldid=2637640
• Jednoduchost, čitelnost
–Blízké uvažování člověka (zadání)
–Silné prostředky pro abstrakci
• Funkce vyššího řádu
• Velká znovupoužitelnostkódu
–Parametrický polymorfismus
–Líné vyhodnocování
• Stabilita programů
–Silná typová kontrola
–Referenční transparentnost
• Jednodušší formální verifikace programu
Ne tak důležité: jakprogram počítá (akce)
–Programy bývají náročné na systémové prostředky (paměť a procesorový čas)
• Např. QuickSortv jazyce C# provede seřazení prvků „na místě“ (nepotřebuje žádnou paměť navíc)
• Patří do deklarativního paradigma
–Důraz: coprogram počítá (vztah vstup–výstup)
–Ne tak důležité: jakprogram počítá (akce)
• Výpočet pomocí logického odvozování(hledání důkazu)
–Většinou se používá tzv. predikátová logika prvního řádku
• Asi nejpopulárnější jazyk:
–Prolog
• Prolog(programovací jazyk)
–Vznik 1972
–Název pochází z „PROgrammationenLOGique“ (francouzsky „programování v logice)
–Pro vyzkoušení doporučuji:
• SWI-Prolog
• SWI-Prolog-Editor (jen Windows)
–http://lakk.bildung.hessen.de/netzwerk/faecher/informatik/swiprolog/indexe.html
• Komerční sféra:
–Zpracování přirozeného jazyka
• Projekt Clarissapro Mezinárodní vesmírnou stanici (NASA)
–Řídící systémy, expertní systémy, systémypro podporu rozhodování
• FleetWatch(letectví)
• ARGOS (systém pro podporu rozhodování a krizové řízení –incidenty zahrnující chemické, biologické, radiologické nebo nukleární úniky)
• Prolog lze použít pro řešení problémů, které zahrnují
–Objektya
–Vztahymezi těmito objekty
• Příklad:
–Pepa má knihu.
• Vztah: vlastnictví („má“)
• Objekty: Pepa, kniha
• Vztah je jednosměrný (kniha nemá Pepu).
• Pravidlapopisují vztahy pomocí jiných vztahů
• Příklad:
–Dvě osoby jsou sestry, pokud jsou obě ženy a mají stejné rodiče.
• Dotaz na existenci určitého vztahu
–Odpověď: ano(pravda), nebo ne(nepravda)
• Příklady:
–Má Pepa knihu?
–Jsou Lenka a Hanka sestry?
• Programování v prologu:
–Deklarace faktů (o objektech a vztazích mezi nimi)
–Definování pravidel (dtto)
–Kladení dotazů (dtto)
• Program = skladiště (databáze) faktů a pravidel
Zápis dotazů
Interaktivní dotazovací režimu Prologu je indikován výzvou ?-
Růžové číslo je zde jen číslo řádku (příkazu), tj. nic podstatného
= Má Pepa knihu?
Odpověď (pravda/nepravda) je vždy vztažena kdatabázi. Výsledek je tedy nutné chápat ve smyslu „je/není odvoditelné z databáze“.
Proměnné
Jména proměnných musí začínat velkýmpísmenem. Více výsledků
Prolog vypíše jen první výsledek, hledání dalších výsledků se povolí stiskem; (středníku), ukončení je.(tečka).U pravidel Prolog jako poslední výsledek vypíše false.
• Prolog při hledání řešení (důkazu) používá následující postup:
–Prochází dotaz postupně zleva doprava
–Prohledávání do hloubky(backtracking)
• Strom možností
• Jednotlivá „patra“ stromu odpovídají proměnným vdotazu (X, Y, Z, …)
–Jednotlivé možnosti v rámci patra odpovídají různým možným hodnotám dané proměnné
• Konkrétněji:
–Najde první shodu pro X (unifikace)
• Vyhodnocuje dále zbytek dotazu, přičemž předpokládá, že X má právě tuto hodnotu. Pokud narazí na jinou proměnnou (Y, Zapod.), postupuje stejný způsobem –zanoření o jednu další úroveň. Pokud pro takové X(Y, Z, …) najde řešení (důkaz), ohlásí ho.
–Pokud řešení (důkaz) pro dané Xnenašel, najde další možnou shodu pro X
• Vyhodnocuje dále zbytek dotazu, přičemž předpokládá, že X má právě tuto novou hodnotu.
–Atd.
Proměnné –hledání řešení
• Proč by nás mělo zajímat, jak Prolog hledá řešení? Záleží na tom?
–Argument: Pokud je dotaz/pravidlo logicky správně, pak Prolog přeci musí vždy dojít ke správnému výsledku
• To je pravda, ale vhodnou formulací dotazu/pravidla:
–Lze hledání důkazu urychlit
• Strom všech možností (všech možných hodnot proměnných), se bude procházet efektivněji
–Lze předejít tomu, aby se hledání důkazu zacyklilo (a skončilo pro nedostatek paměti)
• Strom všech možností totiž může být i nekonečný, např. při využití rekurze v pravidlech (viz cvičení)
Dvě osoby jsou sestry, pokud jsou obě ženy a mají stejné rodiče.
SLOŽITĚJŠÍ PŘÍKLAD
• Automatizace vývoje software –Metodiky vývoje software
• Vodopádový model, prototyping, přírůstkový, spirálový, RAD, … –Diagramy (např. UML)
• Diagram tříd, komponent, aktivit, stavový diagram, sekvenční diagram, …
• CASE= ComputerAidedSoftware Engineering
• Komplexní programové systémy pro podporu vývoje softwarové aplikace
–V jednotlivých jeho fázích
–Některé funkce mohou být integrovány dovývojového prostředí (IDE)
• PreCASE –tvorba globální strategie
• UpperCASE –plánování, specifikace požadavků, modelování organizace podniku
–Cíl: analýza organizace řízení projektů, sledování ekonomických ukazatelů, rámcová specifikace požadavků, …
–Dle metodiky vývoje software
• MiddleCASE –detailní specifikace požadavků, vlastní návrh systému, vizualizace, dokumentace
–Procesy, datová úložiště, správa dokumentů a konfigurace, vývoj prototypů, návrh uživatelského rozhraní
–Diagramy tříd, stavové diagramy, …
–Generátory UI (obrazovky, tiskové sestavy), generátory kostry definic dat
• LowerCASE–kódování, testování, údržba
–Reverzní inženýrství
• Zjištění modelu z již existujícího kódu/dat
–Generování kódu
–Řízení testování
–Sledování a vyhodnocování práce systému, vyhodnocování metrik
• Post CASE–zavedení, údržba a další rozvoj systému
• Centrální úložiště(databáze, slovník, repository)
–Datové struktury a jejich vzájemné vztahy
–Kontrola kvality (konzistence, normalizace)
• Například:
–Odvozování (generování) vztahů/dat
–Upozorňování na chybějící data (definice)
–Upozorňování na špatná data (nekonzistence)
–Mazání odkazů na odstraněný objekt
–Zabránění nekorektním akcím s daty
Velké projekty = více lidí potřeba podpory práce v týmu
–Komunikace přes síť (zpravidla client-server)
• Výměna dokumentů atd.
–Centrální úložiště
• Verzování
• Řízení přístupu (přístupová práva)
• Replikace, synchonizace
–Řízení týmové práce
• Evidence, úkoly, odhadování pracnosti (metriky), … Generování:
–Kostry zdrojového kódu a struktura dat
• Např. hlavičky funkcí, definice tříd, rozdělení na moduly, databázové schéma atd.
–Aplikačních rozhraní (komponent)
–Uživatelských rozhraní aplikace
• Obrazovkové formuláře
• Tiskové sestavy
• Lze ukázat zákazníkovi (prototyping)
–Dokumentace Modelování, vizualizace
–Struktura podniku
–Projekty, procesy
–Datové struktury a vztahy mezi nimi
–Diagramy…
• Forwardengineering(dopřednéinženýrství)
–Model (diagram) kód (program, SQL)
• Reverse engineering(zpětné inženýrství)
–Kód Model (diagram)
• Synchronizacemodel ↔ kód
–Když udělám změny v modelu
–Když udělám změny v kódu
• Nezaručí bezchybný vývoj aplikací
• Můžou vyžadovat velice odborné znalosti
–Např. při analýze, modelování, …
• Nutno posoudit vhodnost použitých metod, na kterých je CASE založen
• SybasePowerDesigner
• RationalRose (IBM)
• SelectArchitect
• EnterpriseArchitect(SparxSystems)
• Oracle Designer
• ArgoUML(freeware)
MySQLWorkbench MySQLWorkbench5.2.47
–CommunityEdition(zdarma –GNUGPL)
–http://dev.mysql.com/downloads/tools/workbench/5.2.html
• ZIP Archive, 30 MB
• Ukázka:
–Data Modeling: EER* diagramy EER Model
• Data Modeling CreateNew EER Model Adddiagram
• Ovládání:
–Placea New Table = T
–Edit table = dvojklik na záhlaví tabulky
• Nastavení zobrazení:
Ukázka: knihovna
• Databáze pro knihovnu:
–Knihy (identifikovány pomocí ISBN)
–Autoři (identifikováni číslem)
–Informace o knize
• Velká data, proto v samostatné tabulce
–Jednotlivé výtisky knihy
• Použité datové typy:
–INT = celé číslo
–CHAR(13) = 13znaků
–VARCHAR(200) = až 200 znaků
Knihovna
Vztahy mezi tabulkami
Vybrat typ vztahu, klepnout na záhlaví jedné tabulky, klepnout na záhlaví druhé
• Kardinalita vztahu:
–Kniha a Výtisk = 1 : n
–Kniha a Autor = n : m
–Kniha a Knihainfo= 1 : 1(identifikující)
• Realizaci vztahu zařídí program:
–Přidáním cizího klíče
–Vytvořením nové tabulky
Vztahy mezi tabulkami
Vztahy mezi tabulkami
Pokud se spleteme (např. vztah 1 : n uděláme naopak), lze vztah jednoduše odstranit
–Pravým tlačítkem na čáru vztahu Delete
–Program umí automaticky odstranit příslušný cizí klíč:
Vizualizace, editace
• Vizualizace (přehlednost):
–Můžu si tabulky rozdělit do skupin (layers)
–Export jako obrázek (PNG, SVG)
• Lze poslat/ukázat zákazníkovi…
• Editace:
–Pokud se spleteme, můžeme poslední akci vrátit (Edit Undo)
Ukázka skupin
Forward/ reverse engineer
• Generování SQL kódu do souboru:
–File Export ForwardEngineerSQL CREATE Script
• Práce s živou databází*:
–Database ForwardEngineer
• Vytvoří tabulky v databázi (podle diagramu)
–Database Reverse Engineer
• Načte strukturu tabulek z databáze a vytvoří podle ní model (diagram)
* Vyžaduje mít spuštěnou databázi MySQL