Vítejte ve třetím dílu malého seriálu o jazyku Object Pascal určeném pro začátečníky. V tomto dílu bych chtěl začít se základními pojmy z objektově orientovaného programování (OOP), protože OOP by dnes do základů programování jistě patřit mělo. Něco z OOP si pak hned vyzkoušíme v Pascalu. Nejdřív ale malé opakování pojmů z minulého dílu a ještě také další část povídání o datových typech v Pascalu, tedy "Typy 2. část". Je toho dost, tak s chutí do práce.
Třetí díl seriálu rozdělím do tří kapitol: v první připomenu úlohy z minula, ve druhé kapitole budeme pokračovat s datovými typy v Pascalu (po rozsahu hodnot typů se nyní zaměříme na povolené operace s typy). No a ve třetí kapitole se pokusím o úvod do pojmů OOP. Je to tedy zase delší povídání, tak si udělejte dobrý zelený čajík, kafe apod. a snažte se vydržet :-P
1. kapitola: Opakování, řešení úloh z 2. dílu
Datové typy
Víme už, že každá proměnná v Pascalu musí mít určeny tři věci:
- velikost proměnné (počet bytů), aby si program mohl pro proměnnou na začátku rezervovat vhodné místo v paměti
- přípustné hodnoty (např. celá čísla, desetinná čísla, znaky, řetězce znaků atd.)
- přípustné operace, které lze s danou proměnnou provádět (např. násobení, dělení, nalezení bezprostředního následníka, nalezení bezprostředního předchůdce, výpočet odmocniny…)
Všechny tyto údaje jsou shromážděny v tzv. datovém typu. Minule jsme se zabývali jednoduchými typy (integer, real, výčet, interval, boolean) a to z hlediska velikosti proměnné v paměti a hlavně přípustných hodnot. V tomto dílu se za chvíli budeme věnovat operacím u jednotlivých typů.
V minulém dílu jsem zapomněl uvést paměťové nároky pro proměnnou typu real. V Delphi je to 8 B čili 64 bitů, takže číslo je počítáno s přesností na 15-16 míst. Dají se ale opět použít i další varianty typu real, třeba typ extended zabírá v RAM 10 B (80 b) a jde o čísla s přesností na 19-20 míst.
Programy z minulého dílu
Pokud jste si vyzkoušeli a promysleli program na výpočet faktoriálu, setkali jste se se dvěma typy cyklů v Pascalu: cyklus for a cyklus repeat. Podrobněji se jimi budeme zabývat později.
Další zadání bylo napsat jednoduché prográmky pro vyzkoušení základních typů:
- Program měl požadovat zadání celého čísla a vypsat jeho druhou a třetí mocninu (vše může být integer).
- Program měl požadovat zadání libovolného čísla a vypsat jeho druhou odmocninu (bude potřeba typ real, pro výpočet odmocniny použijte funkci sqrt, kterou Delphi nabízí, např. příkazem odmocnina := sqrt(cislo);.
- S použitím cyklu, třeba for, napsat program, který například zjistí, jestli zadané číslo je prvočíslo.
Uvedu 2. a 3. program. Řešení mohlo vypadat třeba takto (možností zápisu je víc, snažme se hlavně o přehlednost kódu):
2. program: soubor s názvem například P_odmocnina.dpr
program P_odmocnina;
{$APPTYPE CONSOLE}
uses SysUtils;
var cislo, odmocnina: real;
// zde se jistě hodí typ pro reálná čísla
begin
writeLn('Program pro vypocet druhe odmocniny');
write('Zadej libovolne cislo: ');
readLn(cislo);
odmocnina := sqrt(cislo);
writeLn('Odmocnina z cisla ', cislo:3:3, ' je ', odmocnina:3:9);
readLn;
end.
Při ukládání programu v Delphi jsem nejdřív zvolil pojmenování programu odmocnina.dpr, ale Delphi po spuštění program nepřeložilo a zahlásilo chybu Identifier redeclared: 'odmocnina'. Přijdete na to proč? (odpověď č. 1 je na konci textu).
Poznámka pro milovníky matematiky: Třeba pro výpočet 3. odmocniny už Pascal (a tuším ani ostatní jazyky) speciální funkci v základní výbavě nemá. Šlo by to určitě tak, že bychom využili toho, co pro zjednodušení práce s mocninami a odmocninami vymysleli matematikové už před několika sty lety: logaritmů a inverzní funkce k nim: exponenciální funkce. Ty obě mezi funkcemi Pascalu jsou: ln(x) a exp(x). Nezkusíte si s jejich pomocí naprogramovat třetí odmocninu?
3. program: tento úkol byl daleko těžší, možná až moc. Vždyť některé věci, které byly potřeba, se objeví až v dnešním dílu. Možná jste ale studovali i někde jinde (některé dobré tipy k samostudiu uvádím na konci dílu) a třeba jste to zvládli. Pak gratuluji!
Zde uvádím zatím jen co nejjednodušší řešení, které sice bude fungovat, ale měli bychom ho ještě hodně vylepšit - zefektivnit! Zkuste různá zlepšení promyslet a naprogramovat! Ještě se k tomuto programu vrátíme.
program P_prvocislo;
{$APPTYPE CONSOLE}
uses SysUtils;
var n, i: integer; // n je zkoumané číslo, i je řídící proměnná cyklu
jePrvocislo: boolean; // uchová informaci o vysledku
begin
write('Zadej zkoumane prirozene cislo: ');
readLn(n);
jePrvocislo := true;
for i := 2 to n div 2 do
begin
if n mod i = 0
then jePrvocislo := false;
end;
if jePrvocislo = false
then writeLn('Cislo ', n, ' neni prvocislo.')
else writeLn('Cislo ', n, ' je prvocislo.');
readLn;
end.
Pokud se na toto řešení dívá už někdo pokročilejší, ježí se mu asi vlasy hrůzou na hlavě. Jak už jsem napsal výše, je na tom hodně co zefektivňovat, ale aspoň o tom můžete sami přemýšlet do příště :-).
2. kapitola: Datové typy - 2. část, povolené operace
K paměťovým nárokům a rozsahům hodnot u proměnných různých - zatím jednoduchých - datových typů přidejme dnes povolené operace s proměnnými daného typu.
Operace u typu integer (celá čísla):
- Operace +, -, * ... sčítání, odčítání, násobení.
- Operace (neboli funkce) abs(x), sqr(x) ... výpočet absolutní hodnoty a druhé mocniny z čísla x.
- Operace (funkce) div a mod ... výpočet celočíselného podílu a zbytku při dělení celých čísel.
Příklady: nejdřív celočíselný výsledek dělení: 8 div 2 = 4 (a zbytek je 0), 9 div 2 = 4 (zbytek 1) a teď ty zbytky: 8 mod 2 = 0, 9 mod 2 = 1. - Operace ord(x), pred(x), succ(x) ... nalezení ordinální hodnoty čísla (to je zde číslo samo), předchozího čísla a následujícího čísla. Tyto funkce nejsou u typu integer důležité, ale mohou se hodit u dalších ordinálních typů (viz předchozí díl, prvky mají své pořadí).
- Funkce odd(x) ... určuje, jestli je číslo x liché, nebo sudé. Pro liché x je výsledkem funkce hodnota true, pro sudé false. Příklad: odd(5) vrátí true, odd(6) vrátí false.
- Pro porovnání čísel se používají znaménka <, >, = (menší, větší, je rovno), <=, >= (menší nebo rovno, větší nebo rovno), <> (nerovná se).
K operacím s čísly typu integer zkuste naprogramovat několik cvičení:
- Úkol 1: Napište program, který po zadání čísla vypíše, jestli je zadané číslo liché nebo sudé.
- Úkol 2: Napište program, který po zadání čísla vypíše, jestli je zadané číslo dělitelné třemi.
- Úkol 3: Napište program, který po zadání čísla vypíše, jestli je zadané číslo dělitelné třemi, a pokud není dělitelné třemi, vypíše zbytek při tomto dělení.
- Úkol 4: Napište program, který požádá uživatele o zadání dvou čísel - první bude dělitel a druhé dělenec. Program poté vypíše, jestli je druhé zadané číslo dělitelné prvním (dělitelem), popř. vypíše i zbytek při dělení, pokud číslo dělitelem dělitelné není.
Operace u typu char (character, znak):
- Operace (funkce) chr: zadáme li číslo znaku dle ASCII tabulky, je hodnotou této funkce znak odpovídající tomuto číslu. Př.: chr(64) odpovídá znaku ‘@‘, chr(39) zase apostrofu atd. (Obdobně funguje v text. editorech levý Alt + číslo z numerické klávesnice).
- Operace (funkce) ord: jejím výstupem je ordinální číslo znaku v kódovací tabulce. Např. ord(‘@‘) vrací 64, ord(‘\‘) vrací 92, ord(‘{‘) vrací 123, ord(‘}‘) vrací 125, ord(‘[‘) vrací 93 atd.
- Stejně jako funkce chr funguje číslo napsané za znakem #. Př.: #64 ... znak ‘@‘, #93 ... znak ‘]‘. Takže třeba příkaz write(#56) vypíše stejně jako příkaz write(chr(56)) středník. Lze to však zapsat i takto: write(‘;‘).
- Jako u ostatních ordinálních typů, fungují i u typu char funkce pred a succ pro určení předchůdce a následovníka. Hodnoty typu char lze dokonce porovnávat relačními operátory >, <, >=, <=, =, < >. Např. podmínka ( ‘}‘ > ‘{‘ ) má hodnotu true.
Operace u typu real (reálná čísla, přesněji racionální jen s jistou přesností).
- Stejně jako u typu integer platí pro čísla typu real operace +, -, * ... sčítání, odčítání, násobení, dále abs a sqr (absolutní hodnota a druhá mocnina).
- Dělení zapisujeme lomítkem /. Šlo by použít i pro čísla integer, ale výsledkem dělení je vždy číslo typu real, i kdyby byl výsledek celočíselný!
Př.: přiřazovacím příkazem m:=i/j, kde i = 8 a j = 4, přiřadíme proměnné m sice číslo 2, ale proměnná m musí být typu real. Pokud by byla deklarována jako integer, program by nahlásil chybu! - Nové u real jsou operace sqrt(x) - vypočte druhou odmocninu z čísla x, operace pro goniometrické funkce sin(x), cos(x), pro logaritmus ln(x) (jde o přirozený logaritmus se základem e) a pro exponenciální funkci se v Pascalu používá zápis exp(x) (v matematice ex). V Pascalu (a asi ani jinde?) není definována funkce pro tangens, ale víme přece, že tg(x) = sin(x)/cos(x), u funkce cotg(x) převráceně.
- Nové jsou také funkce trunc(x) a round(x). První vrátí celou část čísla x (truncate – odseknout), druhá číslo x zaokrouhlí. Pozor: číslo x musí být tedy typu real, ale hodnoty těchto funkcí jsou typu integer (lze je ovšem přiřadit i proměnným typu real). Potřebujeme-li celou část čísla x přímo jako číslo typu real, použijeme funkci int(x), pro zjištění desetinné části čísla x funkci frac(x) (fraction). Tyto dvě funkce původní Pascal neměl, objevily se až v Borland Pascalu. Podobně funkce pi, která vypíše hodnotu čísla pí.
- x := 2.526; write(trunc(x)); … vypíše číslo 2, i:=trunc(x) … i má hodnotu 2, proměnná i mohla být deklarované jako integer i jako real, x ovšem jen jako real.
- x:=2.526; write(round(x)); … vypíše 3. Pro typ případné proměnné platí totéž.
- x:=2.526; r:=frac(x); write(r); … vypíše číslo 0.526. Proměnná r musí být real.
- Pozor: pro čísla typu real nelze užít operace mod a div, která známe z typu integer. Nejde tedy zapsat 2.526 mod 3, nebo r div s, pokud r i s nejsou typu integer.
- Jednotlivá čísla typu real nemají své ordinální hodnoty (pořadí), na to je jich příliš mnoho, bylo by to moc pracné. Typ real tedy není ordinální. Nelze u něj tedy použít funkce pred a succ. Relační operátory >, <, >=, <=, =, < > však samozřejmě fungují.
Také k operacím s čísly typu real doporučuji zkusit nějaká cvičení:
- Úkol 5: Sestavte program, který po zadání dvou celých čísel (typu integer) přiřadí jejich součet, součin a podíl do nových proměnných s názvy soucet, soucin, podil (promyslete jejich typy) a vypíše je.
- Úkol 6: Upravte program tak, aby u podílu čísel spočetl také jeho celočíselnou část a zaokrouhlenou hodnotu, přiřadil je do proměnných celaCast, zaokrouhleno a opět vypsal.
- Úkol 7: Napište program, který vypíše hodnoty funkce sinus, kosinus a tangens v intervalu 0° až 90° po 1°. Zjistíte jistě brzy, že funkce sin a cos počítají pouze s úhly v jednotce ... (dokončení v odpovědi č. 2 na konci lekce).
Poznámka: U dost časté úlohy – zjištění, zda jedno celé číslo (a) je dělitelné druhým celým číslem (b), je výhodnější (pro program rychlejší) podmínku zapsat jen pomocí operací s celými čísly div, mod (podobnou podmínku jsem použil výše v programu pro hledání prvočísla), např.:
if a mod b = 0 then write(a, ‘ je dělitelné číslem ‘, b);
Je to lepší způsob než používat funkci trunc, která je určena pro čísla typu real a odsekne z nich část za desetinnou čárkou, např.:
if a/b = trunc(a/b) then write(a, ‘ je dělitelné číslem ‘, b);
Počítání s reálnými čísly (zde a/b) je totiž pro počítač náročnější, než práce s čísly celými.
Pro zájemce o další zkoušení cyklů ještě další úkoly navíc:
- Úkol 8: Napište program, který vypíše postupně všechny dělitele zadaného čísla v rozsahu od 1 do 100. Pro zjištění, zda zkoušené celé číslo (proměnnou označte třeba i) je dělitelem zadaného celého čísla (označte n) vyzkoušejte postupně oba způsoby zápisu podmínky, jak jsou uvedeny v předchozí poznámce (budete mít tedy dva různé programy). Nakreslete si nejdřív vývojový diagram k tomuto programu (stačí jeden).
- Úkol 9: Napište program, který vypíše postupně všechny dělitele zadaného čísla v rozsahu od 1 do zadané horní meze (označte například m). Pro zjištění, zda zkoušené celé číslo (proměnnou označte i) je dělitelem zadaného celého čísla (n) vyzkoušejte opět oba způsoby zápisu podmínky, jak jsou uvedeny v předchozí poznámce (budete mít tedy 2 různé programy).
Pokud to s programováním myslíte vážně (přitom je to myslím docela zábava!), tak příkladů vyřešte co nejvíc.
Teď se ale už pusťme do třetí kapitoly dnešní lekce, a to do prvního povídání o OOP.
3. kapitola: Úvod do OOP
Úvod (úvodu): Proč OOP?
OOP znamená objektově orientované programování. Proč OOP? Jde o další krok ve zvýšení produktivity programování. Problém je v tom, že:
„Cena návrhu programu a jeho vytvoření postupně zcela převládla nad cenou strojového času počítače a nad původním nedostatkem prostředků (paměti, rychlosti počítače), a tak cesty k usnadnění práce programátora se staly v programování nejdůležitější“
Tuto i některé další formulace jsem si dovolil převzít hlavně z knih Rudolfa Pecinovského, např. Objektové programování 1, Grada, 1996 nebo Myslíme objektově v jazyku Java, Grada, 2004.
Poznámka: Procedurální programování. OOP navazuje na předchozí vylepšení - procedurální programování - tedy psaní programu pomocí procedur a funkcí, se kterým přišly vyšší programovací jazyky v 60. a 70. letech (Basic, Pascal, C...). I s procedurami a funkcemi se brzy seznámíte, také se nám budou hodit. Program je složen ze samostatnějších bloků, procedur či funkcí, které lze opakovaně na různých místech použít (vyvolat). Procedurální programovací jazyky přinesly ve své době další velký nárůst v produktivitě programátorovy práce na cestě psát snáze stále složitější programy. I to však časem přestalo stačit...
Cesta k OOP. Pan Pecinovský ve své knize Myslíme objektově v jazyku Java 5.0 velmi pěkně píše:
„Prakticky každý program zaznamená během svého života řadu změn. Tak, jak se průběžně mění požadavky zákazníka … je program postupně upravován, rozšiřován a vylepšován. Celé současné programování je proto vedeno snahou psát programy nejenom tak, aby pracovaly efektivně, tj. rychle a s minimální spotřebou různých zdrojů, ale aby je také bylo možno kdykoliv jednoduše upravit a vylepšit.“
Pak dodává a čtenáři klade na srdce tento citát:
„Napsat program, kterému porozumí počítač, umí i hlupák.
Dobrý programátor píše programy, kterým porozumí i člověk.“
A právě těmto požadavkům vyhovělo OOP.
Vznik OOP: Objektově orientované jazyky byly vyvinuty v 70. a 80. létech 20. století. Prvním byl jazyk Simula 67, dál systém Smalltalk. Na ně navázaly jazyky C++ (objektové rozšíření jazyka C) a podobně objektové verze Pascalu. Podstatou OOP je, že jednotlivé části programu – objekty – jsou ještě samostatnější, univerzálnější a dají se snáze opakovaně i v různých programech využít. OOP se stalo další revolucí v tvorbě programů pro počítač.
Základní vlastnosti OOP
Často se uvádějí tři základní vlastnosti:
- Zapouzdření (encapsulation).
- Dědičnost (inheritance).
- Mnohotvarost (polymorfismus).
Meilir Page-Jones v důkladné a vtipně napsané knize Základy objektově orientovaného návrhu v UML uvádí podstatných vlastností více, ale i méně! Píše toto:
„Když jsem vstoupil do království OOP, rozhodl jsem se vytvořit definici „objektové orientace“ jednou provždy. Sehnal jsem asi tucet chlapíků z objektově orientovaného světa a zamkl je v pokoji bez jídla a bez vody. Řekl jsem jim, že je pustím ven až poté, co se dohodnou na definici, kterou bych mohl předat žádostivě čekajícímu softwarovému světu. Po hodině křiku a rachotu v pokoji následovalo ticho. Protože jsem se bál nejhoršího, opatrně jsem odemkl dveře a nahlédl na potenciálně krvavou scénu. Všichni guru byli naživu, seděli však samostatně a nikdo s nikým nemluvil. Zřejmě každý z nich začal sezení tím, že se snažil ustanovit definici objektové orientace pomocí časem dobře prověřené vědecké praxe hlasitého a neustálého opakování svého tvrzení. Když tento postup nikam nevedl, všichni souhlasili s vytvořením seznamu vlastností objektově orientovaného prostředí, které sami jednotlivě považovali za nezbytné. Každý z nich vytvořil seznam šesti až deseti základních vlastností.
V tomto okamžiku měli zřejmě dvě volby: Mohli vytvořit jeden dlouhý seznam, který by byl souhrnem všech jednotlivých seznamů, nebo mohli vytvořit krátký seznam, který byl průsečíkem jejich seznamů. Zvolili druhou možnost a výsledkem byl krátký seznam vlastností, které se nacházely na všech jednotlivých seznamech.
Ten seznam byl opravdu krátký. Bylo to slovo zapouzdření.“
Potom autor uvádí svůj seznam vlastností softwaru, které tvoří základ objektové orientace. A těch je devět:
Zapouzdření, Skrývání informací a implementací, Zachování stavu, Identita objektů, Zprávy, Třídy, Dědičnost, Mnohotvarost, Obecnost.
Není to s tím OOP asi úplně jednoduché. Ale bez OOP to už dnes v opravdovém programování nejde, takže stojí za to do věci proniknout. A v tom Vám snad může pomoci i tento díl našeho začátečnického kurzu: půjde jen o základní úvod, který se dá dobře pochopit. Zatím se budeme věnovat právě jen zapouzdření.
Zapouzdření
V předchozím procedurálním programování byly proměnné vždy nějakého datového typu (integer - celá čísla, real - reálná nebo prakticky spíš racionální čísla, pole, záznam a další. V tomto dílu si o typech ještě něco povíme). Tím bylo dáno, jakých povolených hodnot může proměnná nabývat. Nebylo však nijak určeno, jaké věci se s proměnnou dají v programu dělat, což mohlo vést k chybám a nepřispívalo to k produktivitě programů.
Problémy před OOP: Mohli jsme mít třeba proměnnou den (z datumu), která byla typu integer, čili celá čísla. Program pak (pokud to nezařídíme) není chráněn před tím, aby do proměnné někdo omylem nezadal třeba nesmyslné číslo 33. A docela dobře by se mohlo stát, že by se někde v programu použila pro číslo dne (např. 18) třeba matematická operace faktoriál, což sice u celého čísla jde, ale jistě to nemá smysl u čísla, které udává den v měsíci.
Objekt, jeho atributy a metody. V OOP budeme mít objekt (např. Datum), který má určena nejen svá data neboli atributy (měsíc, den, rok), ale i metody (schopnosti), kterými může s daty nakládat. Jiné operace prostě použít nelze! Určitě by mezi tyto metody nepatřil faktoriál, ale třeba nastavení data, zároveň zajištění toho, aby zadaný počet dnů v měsíci odpovídal kalendáři, dál třeba zjištění, zda daný rok není přestupný atd.
Zapouzdření. Data (vlastnosti, atributy objektu) jsou tedy zapouzdřena i s metodami (schopnostmi) do jednoho celku. Důsledkem je zpřehlednění, větší bezpečnost práce v programu (ochrana před nepovolenou, chybnou změnou dat v objektu) a také snazší použití, a to i v jiných programech.
Přístupová práva. Bezpečnost se v OOP zvýší ještě tím, že se atributům a metodám přiřazují různá přístupová práva. Ta jsou hlavně tato: public (veřejný), private (soukromý, manipulovat může jen samotný objekt) a protected (chráněný, souvisí až s dědičností).
Pěkný příklad přístupových práv z literatury: Vezměme jako objekt jakýsi dům, třeba váš. Takový objekt by mohl mít vlastnosti dveře, okna, židle, postele, záchod atd. Potom by mohly mít vstupní dveře přístupové právo public, ale záchod bude private. Pokud bychom ale vytvořili zvláštní případ domu, třeba veřejné WC, pak u něj změníme i právo záchodu na public (to může také odpovídat druhé vlastnosti OOP, dědičnosti, možná i tomu, že se objekty stejného typu mohou chovat různě, což by zase byl příklad mnohotvarosti. To se nás ale ještě netýká).
Ještě lepší by bylo, kdyby všechny atributy, čili dveře, okna, židle, postel, pyžamo atd. byly private - jsou přece naším majetkem! A k nim vytvoříme povolené - public metody, např. otevřiDveře, zavřiDveře, sedniNaŽidli, asi i použijZáchod (přijde třeba návštěva). Ovšem metoda oblečPyžamo nebo lehniDoPostele by asi měla zůstat private.
Jiný příklad objektu už známe: objekt Datum. Ten by mohl mít atributy den, měsíc a rok a metody nastavDen, nastavMesic, nastavRok, nastavCeleDatum, dejDen, dejMesic, dejRok, dejDatum, zjistiJeRokPrestupny, dejJeRokPrestupny (možná i další). Např. metoda nastavDen pak už umožní jedině správné nastavení dne (do čísla 31, popř. v závislosti na měsíci nebo i na přestupnosti roku ještě přesněji), jiné hodnoty odmítne. A přístupová práva? Nejlepší by bylo, aby atributy byly všechny private (podobně jako židle, postele, záchod v domě), a metody public, aby se k datům uživatel vůbec dostal. Jen metoda zjistiJeRokPrestupny by mohla být také private – nikomu zvenčí přece nemusíme prozradit, jak takovou operaci provádíme.
Práci s datem ovšem tvůrci Delphi už naprogramovali za nás. Mnoho metod pro práci s časem najdete v jednotce SysUtils, kterou nám Delphi přikládá automaticky k našim konzolovým programům.
Jak by mohla vypadat třída pro práci s datem je ukázáno v knize Myslíme v jazyku Delphi 6, jejímž autorem je Marco Cantù. Třídu nazval TDate, má v sobě zapouzdřený privátní (private) atribut fDate, obsahující datum ve speciálním formátu (datovém typu Delphi) TDateTime, dál několik privátních metod a potom veřejné metody (nastavení data hodnotou den, měsíc, rok, výpis dne, měsíce či roku, zjištění, zda rok je přestupný apod.).
Jak toto přesně vypadá v Delphi, kde je možností nesrovnatelně víc, do toho nám asi tvůrci Delphi nahlédnout nedovolí. Pokud by někdo pokročilejší mohl k tomuto přispět do diskuse, budu rád.
Třída (class), instance třídy (objekt). S OOP je spojen ještě jeden základní pojem, a to třída (class). Je to tak, že nejdřív naprogramujeme třídu s jejími atributy a metodami, a pak teprve v další části programu vytvoříme podle této třídy (jako vzoru) jeden nebo i víc konkrétních objektů. Objekty se také nazývají instance třídy. Třída je tedy jakási forma, podle které se vytvářejí jednotlivé „výrobky“ – objekty.
Poznámky:
- V Delphi se v deklaraci třídy objeví jen hlavičky metod (procedur a funkcí, o tom později, v ukázce na konci to zatím jistě intuitivně pochopíte). Celé definice metod následují až za deklarací třídy.
- Názvy tříd v Delphi začínají obvykle písmenem T, zřejmě ještě ze slova type - datový typ. Např. třída pro práci s datem bude nazvána TDatum.
Tečková notace. Při značení atributů nebo metod dané třídy či objektu se používá tečková notace, např. značení vlastností (čili dat, atributů) v definici třídy TDatum bude TDatum.den, TDatum.mesic. Označení metody této třídy by mohlo být TDatum.nastavRok. Pokud potom v programu vytvoříme podle této třídy objekty (instance) s názvem d1, d2 apod., označení jejich atributů a metod bude třeba d1.den, d1.mesic, d1.nastavRok, d2.dejDen, d3.zjistiJeRokPrestupny apod.
Možná si pojmy ještě jednou promyslete, ale pusťme se hlavně konečně taky do programování. Zkusme v konzole Delphi vytvořit prográmek, který by řešil lineární rovnici a*x + b = 0 (čili při vstupních hodnotách - číslech a, b našel výstupní hodnotu - číslo x.
Nejdřív jakýsi plán na úvod, ten by nám měl dost pomoci:
- Co by měl program umět? Tedy: fáze shromažďování požadavků a analýza požadavků.
Měl by tedy vyřešit lineární rovnici. Bude požadovat zadání dvou koeficientů (a, b) a potom by měl vypsat kořen rovnice, pokud existuje. Nebo napsat, že rovnice kořen nemá. - Jaké třídy (a tím také objekty) v programu použijeme? Tedy: fáze analýzy.
Naštěstí to zde máme velmi jednoduché. Jistě nám postačí jediná třída, kterou naučíme řešit rovnici. Z ní se pak v programu vytvoří objekt, zastupující jednu konkrétní rovnici, kterou taky hned vyřeší. Pokud bychom chtěli vyřešit rovnic víc, můžeme si z naší třídy třeba vytvořit víc různých instancí - objektů, v našem případě víc konkrétních rovnic i s řešením. Třídu bych nazval třeba TLinRovnice. - Jak bude třída detailně vypadat (atributy, metody, jejich parametry)? Tedy: fáze návrhu.
Naše třída TLinRovnice by mohla mít dva atributy (vlastnosti, hodnoty zastupované nějakými proměnnými), a to koeficienty. Označím je a, b. Ty budou jistě pěkně zapouzdřené uvnitř, čili private. Dál by mohla mít privátní atribut, zastupující kořen rovnice: x. A ještě metodu najdiKoren(), která kořen vypočte. I tu bych nechal privátní. No a aby bylo vůbec možno se k atributům dostat, musíme nadefinovat také metody veřejné: třeba zadejKoeficienty() a vypisReseni().
Jasnější je to z obrázku, který se snaží vyhovovat značení jazyka UML, který se používá při analýze a návrhu. Znaménko '-' znamená private, '+' public.TLinRovnice - a: real
- b: real
- x: real- function najdiKoren(): real
+ constructor vytvorRovnici()
+ procedure zadejKoeficienty()
+ procedure vypisReseni() - A teď to všechno konečně naprogramovat. Tedy: fáze implementace (konstrukce, programování).
V předchozích bodech se činili analytici, návrháři, softwaroví inženýři (tedy ti nejlépe placení). Teď nastoupí programátoři. Ale jak vidím (a v Delphi zkouším), to už by na tento díl bylo opravdu moc. Nechám to na příště, budeme potřebovat přeci jen ještě pár věcí probrat, tak mezitím naprogramujte předchozí úkoly k datovým typům a popř. studujte další texty k OOP.
Snad Vás tento díl úplně nezdolal? Budu rád, když mi třeba napíšete nějaké postřehy, podněty apod. (kontakty naleznete na mé kartě).
Pojmy k zapamatování:
Měli byste vědět, že s různými datovými typy lze provádět různé operace, nemá jistě cenu se je moc učit zpaměti. Spíše se je snažte co nejvíce používat při psaní kódu!
No a k OOP: atributy (data, vlastnosti), metody (schopnosti). Zapouzdření atributů a metod v objektu. Přístupová práva public a private. Třída, objekt, neboli instance třídy, tečková notace.
Doporučená literatura (weby):
Tentokrát uvedu i nějaké odkazy, které vám mohou pomoci ve studiu (jde o to, kolik času můžete a chcete Pascalu a OOP obětovat).
Hlavně k Pascalu je toho na Internetu moc, doporučuji perfektní velmi důkladný kurz na stránkách Pavla Patáka. Škoda, že je věnovaný ještě staršímu Borland Pascalu, ale velmi ho doporučuji. Jsou zde i kapitoly k OOP, obecnější věci by byly jistě taky dobré, ale do kódu bych se nepouštěl, v Borland Pascalu je u OOP něco jinak než v novějším Object Pascalu, to by Vás mohlo asi plést. Kurz obsahuje i mnoho cvičení, myslím, že i s řešeními.
K OOP je toho na internetu méně. Určitě dobrý bude seriál Učíme OOP R. Pecinovského. K obecným pojmům není špatný na úvod soubor ke stažení Úvodní pojmy z objektového programování. Možná najdete něco dobrého sami: napište do diskuse!
Řešení otázek z tohoto dílu:
- Program nemůže mít ve svém záhlaví stejný název, jako je název nějaké proměnné v programu.
- Funkce sin a cos počítají pouze s úhly v jednotce radián. Převod ze stupňů na radiány třeba takto: stupne := radiany * 180/pi.
To už je dnes opravdu všechno. Mějte se pěkně a neseďte pořád u počítače :-).