Prezentace se nahrává, počkejte prosím

Prezentace se nahrává, počkejte prosím

Rudolf Pecinovský rudolf@pecinovsky.cz Rozhraní Rudolf Pecinovský rudolf@pecinovsky.cz.

Podobné prezentace


Prezentace na téma: "Rudolf Pecinovský rudolf@pecinovsky.cz Rozhraní Rudolf Pecinovský rudolf@pecinovsky.cz."— Transkript prezentace:

1 Rudolf Pecinovský rudolf@pecinovsky.cz
Rozhraní Rudolf Pecinovský

2 Obsah s odkazy Rozhraní × Implementace Interface a jeho implementace
Návrhový vzor Služebník Návrhový vzor Prostředník Návrhový vzor Pozorovatel / Posluchač Návrhový vzor Most Balíčky

3 Rozhraní × Implementace
Signatura × Kontrakt Dokumentační komentáře Zásady správného programování 159–176

4 Trocha mytologie Janus římský bůh vchodů, dveří, počátku a konce
Měl dvě tváře: jedna hleděla do budoucnosti, druhá do minulosti I program má dvě tváře: Rozhraní × Implementace Copyright © 2006, Rudolf Pecinovský VŠE – 03

5 Rozhraní Implementace
Definuje, co bude zbytek programu o dané entitě vědět Všem na sebe všechno řekne Zabezpečuje, aby entita plnila svoji funkci Všechno se snaží maximálně utajit I samotné rozhraní má dvě složky Signatura Specifikuje vlastnosti, které může zkontrolovat překladač (názvy, typy, …) Kontrakt Doplňuje další důležité informace, které však překladač zkontrolovat nedokáže – o jejich dodržení se musí postarat programátor Copyright © 2006, Rudolf Pecinovský VŠE – 03

6 Rozhraní a implementace metody
Rozhraní – signatura Jmenuje se blikni Nemá žádné parametry Nic nevrací Rozhraní – kontrakt Světlo nejprve „rozsvítí“ Nechá je „svítit“ půl vteřiny Po půl vteřině je opět „zhasne“ Implementace K rozsvícení světla používá svoji metodu rozsviť() Půlvteřinové svícení zabezpečí pozastavením programu pomocí metody čekej() třídy IO, které předá počet milisekund čekání Zhasnutí realizuje zavoláním své metody zhasni() public void blikni() { rozsviť(); IO.čekej( 500 ); zhasni(); } Copyright © 2006, Rudolf Pecinovský VŠE – 03

7 Rozhraní a implementace třídy
public class Světlo { private static final Barva ZHASNUTÁ = Barva.ČERNÁ; private final Elipsa žárovka; private final Barva barva; public Světlo() { this( 0, 0 ); } public Světlo( int x, int y ) { this( x, y, Barva.ČERVENÁ ); public Světlo( int x, int y, Barva barva ) { this( x, y, 50, barva ); public Světlo( int x, int y, int průměr, Barva barva ) { žárovka = new Elipsa( x, y, průměr, průměr, barva ); this.barva = barva; public void zhasni() { žárovka.setBarva( ZHASNUTÁ ); public void rozsviť() { žárovka.setBarva( barva ); public void blikni() { rozsviť(); IO.čekej( 500 ); zhasni(); public int getPrůměr() { return žárovka.getŠířka(); public Barva getBarva() { return barva; public boolean isZhasnuté() { return žárovka.getBarva() == ZHASNUTÁ; public Pozice getPozice() { return new Pozice( žárovka.getX(), žárovka.getY() ); public void setPozice( int x, int y ) { žárovka.setPozice( x, y ); public void setPozice( Pozice p) { žárovka.setPozice( p.x, p.y ); Rozhraní – signatura Třída se jmenuje Světlo Třída má metody – 4 přetížené verze konstruktorů – rozsviť(), zhasni() – blikni() – getBarva(), getPozice() – getPrůměr(), isZhasnuté() – setPozice(int,int) – setPozice(Pozice) Rozhraní – kontrakt Co která metoda umí Implementace Používané atributy Realizace jednotlivých metod Copyright © 2006, Rudolf Pecinovský VŠE – 03

8 Kontrakt = dokumentační komentáře
Nejlepší způsob, jak můžeme specifikovat kontrakt, je podrobně jej vypsat v dokumentačním komentáři Dokumentační komentář je součástí syntaxe Javy Začíná /** a končí */ (otevírací a zavírací komentářová závorka) Umisťuje se vždy před dokumentovanou entitu (třídu, metodu, atribut) Publikuje se ve formátu HTML, je v něm možno použít HTML značky (tagy) Může obsahovat speciální vlastní značky s předem definovaným významem Bývá zvykem začínat pokračovací řádky ve zdrojovém kódu hvězdičkou Součástí JDK je program javadoc.exe, který z dokumentačních komentářů vyrobí profesionální dokumentaci Dokumentace k API standardní knihovny je vyrobena právě tímto způsobem Copyright © 2006, Rudolf Pecinovský VŠE – 03

9 Značky v dokumentačních komentářích
Zde budou uvedeny jen ty nejdůležitější, zbytek v učebnicích a v dokumentaci, kterou najdete na adrese <doc>\tooldocs\windows\javadoc.html#javadoctags kde <doc> je složka, kam jste si instalovali dokumentaci Dokumentace třídy: @author – autor třídy (podepisujte své programy) @version – verze programu (uvádějte, budete-li program vylepšovat) Dokumentace metody: @param – význam parametru (název za značku musí být odpovídat názvu parametru v hlavičce metody) @return – popis toho, co metoda vrací Značky v textu komentáře: ?}– text ? bude vysazen neproporcionálním písmem ?}– do vytvořené dokumentace bude vložen hypertextový odkaz na ? Použití dokumentačních komentářů si můžete prohlédnout v projektech vystavených na webu s přednáškami Copyright © 2006, Rudolf Pecinovský VŠE – 03

10 Vytvoření dokumentace v BlueJ
Editor BlueJ zobrazuje Zdrojový kód třídy = její implementaci Dokumentaci třídy = její rozhraní Při první žádosti o zobrazení dokumentace třídy zavolá BlueJ program javadoc a nechá jej dokumentaci vytvořit Vytvořená dokumentace se ukládá do podsložky doc aktuálního projektu Příkazem Nástroje -> Dokumentace projektu je možno požádat o vytvoření dokumentace všech tříd projektu –> ta se pak otevře v implicitním prohlížeči webových stránek Copyright © 2006, Rudolf Pecinovský VŠE – 03

11 Příklad dokumentované třídy 1/2
/************************************************************** * Instance třídy Světlo}</b> představují simulace * rozsvítitelných a zhasnutelných pohyblivých světel. * Rudolf Pecinovský 1.02 */ public class Světlo { //Barva zhasnutých světel společná pro všechny instance private static final Barva ZHASNUTÁ = Barva.ČERNÁ; private final Elipsa žárovka; //Kruh simulující dané světlo private final Barva barva; //Barva rozsvíceného světla /********************************************************** * Vytvoří světlo implicitních rozměrů a barvy * umístěné v imlicitní pozici (levý horní roh plátna). public Světlo() this( 0, 0 ); } Lze použít HTML značky BlueJ barevně odlišuje běžné a dokumentační komentáře Copyright © 2006, Rudolf Pecinovský VŠE – 03

12 Příklad dokumentované třídy 2/2
/********************************************************** * Vytvoří světlo implicitních rozměrů a barvy * umístěné na zadaných souřadnicích. * x Vodorovná souřadnice vytvářeného světla y Svislá souřadnice vytvářeného světla */ public Světlo( int x, int y ) { this( x, y, Barva.ČERVENÁ ); } * Vytvoří světlo implicitních rozměrů zadané barvy x Vodorovná souřadnice vytvářeného světla y Svislá souřadnice vytvářeného světla barva Barva rozsvíceného světla public Světlo( int x, int y, Barva barva ) this( x, y, 50, barva ); Copyright © 2006, Rudolf Pecinovský VŠE – 03

13 Dokumentace uvedené třídy
Copyright © 2006, Rudolf Pecinovský VŠE – 03

14 Dokumentace standardní knihovny
Copyright © 2006, Rudolf Pecinovský VŠE – 03

15 Šablona standardní třídy
/************************************************************ * Instance třídy Šablona} představují ... * jméno autora , */ public class Šablona { //== KONSTANTNÍ ATRIBUTY TŘÍDY ============================== //== PROMĚNNÉ ATRIBUTY TŘÍDY ================================ //== KONSTANTNÍ ATRIBUTY INSTANCÍ =========================== //== PROMĚNNÉ ATRIBUTY INSTANCÍ ============================= //== PŘÍSTUPOVÉ METODY ATRIBUTŮ TŘÍDY ======================= //== OSTATNÍ NESOUKROMÉ METODY TŘÍDY ======================== //########################################################### //== KONSTRUKTORY A TOVÁRNÍ METODY ========================== //== ABSTRAKTNÍ METODY ====================================== //== PŘÍSTUPOVÉ METODY INSTANCÍ ============================= //== OSTATNÍ NESOUKROMÉ METODY INSTANCÍ ==================== //== SOUKROMÉ A POMOCNÉ METODY TŘÍDY ======================== //== SOUKROMÉ A POMOCNÉ METODY INSTANCÍ ===================== //== VNOŘENÉ A VNITŘNÍ TŘÍDY ================================ //== TESTOVACÍ METODY A TŘÍDY =============================== } Copyright © 2006, Rudolf Pecinovský VŠE – 03

16 Třída Světlo ve standardní šabloně
/************************************************************** * Instance třídy Světlo představují simulace rozsvítitelných * a zhasnutelných pohyblivých světel. * Rudolf Pecinovský 1.02 */ public class Světlo { //== KONSTANTNÍ ATRIBUTY TŘÍDY ================================ //Barva zhasnutých světel private static final Barva ZHASNUTÁ = Barva.ČERNÁ; //== PROMĚNNÉ ATRIBUTY TŘÍDY ================================== //== KONSTANTNÍ ATRIBUTY INSTANCÍ ============================= private final Elipsa žárovka; //Kruh simulující dané světlo private final Barva barva; //Barva rozsvíceného světla //== PROMĚNNÉ ATRIBUTY INSTANCÍ =============================== //== NESOUKROMÉ METODY TŘÍDY ================================== //############################################################# //== KONSTRUKTORY A TOVÁRNÍ METODY ============================ /********************************************************** * Vytvoří světlo implicitních rozměrů a barvy * umístěné v imlicitní pozici (levý horní roh plátna). public Světlo() { this( 0, 0 ); } * umístěné na zadaných souřadnicích. x Vodorovná souřadnice vytvářeného světla y Svislá souřadnice vytvářeného světla public Světlo( int x, int y ) { this( x, y, Barva.ČERVENÁ ); /********************************************************** * Vytvoří světlo zadaných rozměrů a barvy * umístěné na zadaných souřadnicích. * x Vodorovná souřadnice vytvářeného světla y Svislá souřadnice vytvářeného světla průměr Průměr kruhu simulujícího světlo barva Barva rozsvíceného světla */ public Světlo( int x, int y, int průměr, Barva barva ) { žárovka = new Elipsa( x, y, průměr, průměr, barva ); this.barva = barva; } //== ABSTRAKTNÍ METODY ======================================== //== NESOUKROMÉ METODY INSTANCÍ ============================== * Simuluje zhasnutí světla vybarvením jeho kruhu * barvou zhasnutého světla. public void zhasni() žárovka.setBarva( ZHASNUTÁ ); * Simuluje rozsvícení světla vybarvením jeho kruhu * barvou rozsvíceného světla. public void rozsviť() žárovka.setBarva( barva ); // ... a další, zde nezobrazené metody Copyright © 2006, Rudolf Pecinovský VŠE – 03

17 Zásady správného programování
Snažit se o maximální přehlednost programu Napsat program, kterému rozumí počítač, umí každý trouba. Dobří programátoři píší programy, kterým rozumí lidé. Martin Fowler, Refactoring Dodržovat zavedené konvence Jsou zveřejněné na Volit smysluplné identifikátory Odsazovat vnitřky všech bloků Důsledně vše komentovat Komentář v kódu nemá popisovat co příkaz dělá (to čtenář vidí), ale vysvětlovat co a proč příkaz/metoda/atribut dělá a proč v programu je Komentujte i soukromé metody a atributy Copyright © 2006, Rudolf Pecinovský VŠE – 03

18 Interface a jeho implementace
Syntaktická definice Modifikátory public a abstract Instance rozhraní Implementace zadaného rozhraní Rozhraní v BlueJ Trocha terminologie Proč používat interface 75–78 260–272

19 Formalizovaný zápis rozhraní – interface
Java zavedla speciální konstrukci umožňující deklarovat rozhraní bez jakékoliv zmínky o implementaci Konstrukce dostala název interface – je to vlastně třída bez implementace Signatura rozhraní je dána deklaracemi metod a statických konstant (konstanty se nedoporučuje používat) Kontrakt je (stejně jako u standardních tříd) definován prostřednictvím dokumentačních komentářů Také interface je třeba přeložit, po překladu má vlastní soubor .class V diagramu tříd je doplněn stereotypem «interface» Copyright © 2006, Rudolf Pecinovský VŠE – 03

20 Příklad zdrojového kódu rozhraní
public interface ISemafor { /** Rozsvítí oranžové světlo. */ public void pozor(); /** Rozsvítí červené světlo. */ public void stop(); /** Rozsvítí rozsvíté červené + oranžové světlo. */ public void připravit(); /** Rozsvítí zelené světlo. */ public void volno(); /** Zhasne všechna světla. */ public void nic(); /** Projde postupně celým cyklem s implicitními dobami trvání stavů. */ public void cyklus(); /** Projde postupně celým cyklem se zadanými dobami trvání stavů. pozor Doba, po níž bude svítit samotná oranžová stop Doba, po níž bude svítit samotná červená připravit Doba, po níž bude svítit červená s oranžovou volno Doba, po níž bude svítit samotná zelená */ public void cyklus( int pozor, int stop, int připravit, int volno ); } Metody nemají implementaci = tělo, jsou pouze abstraktní – místo těla mají středník Copyright © 2006, Rudolf Pecinovský VŠE – 03

21 interface – syntaktické definice
Rozhraní: [ Modifikátor_přístupu ] interface Název_rozhraní ¶ [extends Název_rozhraní [, Název_rozhraní ] …] ¶ { [ Deklarace ]… } Deklarace: Deklarace_třídní_konstanty Deklarace_metody Definice_vnořené_třídy Deklarace_metody: [ Modifikátor ]… Typ_návratové_hodnoty ¶ Název ( [ Seznam_parametrů ] ) ; Copyright © 2006, Rudolf Pecinovský VŠE – 03

22 Modifikátory public a abstract
Modifikátor public Všechny metody deklarované rozhraním jsou povinně public Protože rozhraní neveřejné metody mít stejně nemůže, povoluje syntaxe modifikátor public nepsat Implementující třídy jej však u svých metod uvádět musí => doporučuji jej psát – pak se dá z rozhraní snáze kopírovat Modifikátor abstract Všechny metody deklarované rozhraním jsou abstraktní (jsou to pouze deklarace bez implementace) Kdybychom takovou metodu deklarovali ve třídě, museli bychom u ní uvést modifikátor abstract Protože rozhraní konkrétní (tj. implementované) metody mít stejně nemůže, povoluje syntaxe modifikátor abstract nepsat Implementující třídy jej musí své metody implementovat => nebudou abstraktní => doporučuji neuvádět modifikátor abstract ani v rozhraní – pak se dá z rozhraní snáze kopírovat Copyright © 2006, Rudolf Pecinovský VŠE – 03

23 Rozhraní a jeho instance
Rozhraní (interface) nemá žádnou implementaci => nemůže mít ani vlastní instance Instance se musí vyrobit; jakmile se má něco dělat, přijde ke slovu implementace, a tu rozhraní nemá Rozhraní je jako politik či ideolog: vyhlásí, jak má něco vypadat a jak se to má chovat, ale odpracovat to musí někdo jiný Třída se může přihlásit k tomu, že implementuje dané rozhraní Přihlašuje se k tomu veřejně ve své hlavičce; tím se toto prohlášení stává součástí její signatury a překladač bude kontrolovat jeho naplnění Instance třídy, která implementuje nějaké rozhraní, se mohou vydávat za instance daného rozhraní Třída může implementovat několik rozhraní současně, její instance se pak mohou vydávat za instance kteréhokoliv z nich Kdykoliv se hovoří o instanci rozhraní, hovoří se ve skutečnosti o instanci nějaké třídy, která dané rozhraní implementuje Copyright © 2006, Rudolf Pecinovský VŠE – 03

24 Implementace rozhraní třídou 1/2
Hlavička třídy: public class Semafor implements ISemafor Má-li být třídě povoleno vytváření instancí, musí implementovat všechny metody, které jí implementovaná rozhraní deklarují Pokud tak třída neučiní, musí se sama prohlásit za abstraktní a nemůže mít vlastní instance Třídu, která může vytvářet své instance, (tj. má implementované všechny metody, které slíbila implementovat), označujeme jako konkrétní Copyright © 2006, Rudolf Pecinovský VŠE – 03

25 Implementace rozhraní třídou 2/2
Deklarovaná metoda, kterou musí všechny implementující třídy implementovat Copyright © 2006, Rudolf Pecinovský VŠE – 03

26 Rozhraní v BlueJ (Demo)
Rozhraní vytváříme stejně jako třídu, pouze v dialogovém okně nastavíme přepínač Typ třídy na hodnotu Rozhraní Implementaci rozhraní zadáme Ručně přímým zápisem v kódu Natažením šipky od třídy k implementovanému rozhraní Implementaci rozhraní zrušíme Ručně přímým smazáním v kódu Klepnutím na šipku (tím ji vybereme) a zadáním příkazu Odstranit z její místní nabídky Demo: A06_1_Rozhraní.htm Copyright © 2006, Rudolf Pecinovský VŠE – 03

27 Trocha terminologie API – Application Programming Interface
Aplikační programátorské rozhraní – rozhraní určené pro programátory, jejichž programy s danou aplikací komunikují V Javě je vytváříme z dokumentačních komentářů programem javadoc Zahrnuje signaturu i kontrakt GUI – Graphical User Interface Grafické uživatelské rozhraní – definuje formu prezentace výsledků a způsob komunikace uživatele s programem GUI nemá žádnou přímou vazbu na API Rozhraní × interface Pod termínem rozhraní budu rozumět souhrn informací, které o entitě její okolí ví, tj. signaturu + kontrakt Termín interface budu používat, když budu hovořit o programové konstrukci Nebude-li hrozit nedorozumění, budu i pro interface používat termín rozhraní Copyright © 2006, Rudolf Pecinovský VŠE – 03

28 Proč používat interface
Odděluje třídy, které by na sobě jinak vzájemně závisely, a umožňuje je pak měnit nezávisle na sobě (viz NV Most) Umožňuje deklarovat požadované vlastnosti zpracovávaných objektů bez ohledu na to, čí instancí tyto objekty budou (viz NV Služebník) Umožňuje definovat obecněji koncipované služby (metody) Umožňuje zobecnit společné vlastnosti skupiny tříd a definovat pak metody schopné pracovat s instancí kterémkoliv třídy z dané skupiny Copyright © 2006, Rudolf Pecinovský VŠE – 03

29 Příklad – rozhraní ITvar v projektu Tvary
Copyright © 2006, Rudolf Pecinovský VŠE – 03

30 Návrhový vzor Služebník
Motivace Implementace Diagramy tříd obou možných užití Příklad: Plynule posuvné tvary Příklad: Blikající světlo 286–290

31 Služebník – motivace Několik tříd potřebuje definovat stejnou činnost a nechceme definovat na několika místech stejný kód Objekt má úkol, který naprogramovat buď neumíme, nebo bychom jej sice zvládli, ale víme, že je úloha již naprogramovaná jinde Řešení: Definujeme či získáme třídu, jejíž instance (služebníci) budou obsluhovat naše instance a řešit úkoly místo nich Řešení pak bude na jednom místě a bude se snáze spravovat Postup se hodí i když připravujeme řešení, které chceme definovat dostatečně obecné, aby je mohli používat všichni, kteří je budou v budoucnu potřebovat, a přitom nevíme, kdo budou ti potřební Copyright © 2006, Rudolf Pecinovský VŠE – 03

32 Služebník – implementace
Služebník nepracuje sám, ale komunikuje s obsluhovanými instancemi Aby mohl instance bezproblémově obsluhovat, klade na ně požadavky, co všechno musejí umět Služebník proto: Definuje rozhraní, v němž deklaruje své požadavky Jeho obslužné metody budou jako své parametry akceptovat pouze instance deklarovaného rozhraní Instance, která chce být obsloužena: Musí implementovat dané rozhraní, aby se mohla vydávat za jeho instanci Implementací rozhraní deklaruje, že umí to, co od ní služebník k její plnohodnotné obsluze požaduje Copyright © 2006, Rudolf Pecinovský VŠE – 03

33 Služebník – diagramy tříd
Klient posílá zprávu obsluhované instanci a ta předá požadavek služebníku, který jej realizuje; klient nemusí o služebníku vědět Klient posílá zprávu přímo služebníku a v parametru mu současně předává instanci, kterou má obsloužit Copyright © 2006, Rudolf Pecinovský VŠE – 03

34 Příklad 1: Plynule posuvné objekty
Objekty projektu Tvary se umí přesouvat pouze skokem Pokud bychom chtěli, aby se přesouvaly plynule, museli bychom do každého z nich přidat příslušné metody, které by však byly u všech tříd téměř totožné Seženeme si služebníka – instanci třídy Přesouvač Tito služebníci vyžadují od obsluhovaných objektů implementaci rozhraní IPosuvný deklarujícího metody: Pozice getPozice(); void setPozice( Pozice pozice ); void setPozice( int x, int y ); Zato nabízí možnost volat metody: void přesunO ( IPosuvný ip, int dx, int dy ); void přesunNa( IPosuvný ip, int x, int y ); void přesunNa( IPosuvný ip, Pozice pozice ); Copyright © 2006, Rudolf Pecinovský VŠE – 03

35 Příklad 2: Blikající světlo
Chceme po instancích třídy Světlo, aby uměly blikat zadanou dobu nezávisle na jiné činnosti Cyklus je nepoužitelný, protože po dobu jeho provádění ostatní činnosti stojí Takto není možno naprogramovat ukazatel směru jedoucího auta Využijeme služeb instancí třídy Opakovač, jejichž metody umějí opakovat klíčové činnosti svých parametrů Opakovač od obsluhovaných vyžaduje, aby implementovali rozhraní IAkční s metodou akce(), kterou bude opakovač zadaný-počet-krát opakovat Demo: D03-2: Blikání světla Copyright © 2006, Rudolf Pecinovský VŠE – 03

36 Návrhový vzor Prostředník
Mediator Motivace Implementace Příklad: Plátno × Správce plátna 286–290

37 Motivace Objekty se při pohybu nejprve smažou v původní pozici, aby se pak nakreslily v nové; při tom občas odmažou i část svých kolegů Aby objekt mohl zrekonstruovat svůj obraz, musel by mu někdo poslat zprávu Vysílač je vždy závislý na příjemci, protože změna jeho rozhraní může ovlivnit požadovaný způsob zasílání zpráv Když bude každý umět každému poslat zprávu, velmi se zvýší počet vzájemných závislostí, které zhoršují spravovatelnost Každá změna nás nutí zkontrolovat všechny závislé objekty Musí-li se změnit závislý objekt, dominovým efektem se problém propaguje na všechny objekty, které jsou na něm závislé Copyright © 2006, Rudolf Pecinovský VŠE – 03

38 Prostředník – implementace
Obdobný problém byl i u telefonů – obdobné je i řešení Telefony také nejsou spojeny každý s každým, ale spojují se prostřednictvím ústředny Definujeme objekt prostředníka, který zprostředkovává veškerou komunikaci objektů Vzájemné závislosti objektů se tak omezí na závislost na prostředníku V našem projektu nahradíme plátno správcem plátna Má na starosti správný vzhled Když objekt mění svoji podobu, řekne správci Správce pak požádá o překreslení všechny, jichž se to týká Prostředník je většinou implementován aplikací návrhového vzoru Pozorovatel – viz dále Copyright © 2006, Rudolf Pecinovský VŠE – 03

39 Návrhový vzor Pozorovatel/Posluchač
Observer / Listener Motivace Implementace Diagramy tříd obou možných užití Příklad: Blikající světlo Příklad: Plynule posuvné tvary

40 Posluchač – motivace Objekt čekající na výskyt nějaké události – má dvě možnosti: Neustále se ptát iniciátora události, zda už nastala Oslík v 2. dílu Shreka se neustále ptá „Už tam budem?“ Řidič čekající na zelenou neustále sleduje semafor Dohodne se s iniciátorem, že dohodnutým způsobem oznámí, až událost nastane V lůžkovém vlaku vás průvodčí vzbudí před cílovou stanicí Řidič na semaforu v klidu čte mapu v očekávání, že ti za ním na něj zatroubí SMS oznámí příchod peněz na konto Návrhový vzor pozorovatel řeší problém druhým způsobem, je však třeba dohodnout způsob oznámení výskytu události Vzor je někdy označován jako vzor vydavatel—předplatitel (publisher—subscriber) Copyright © 2006, Rudolf Pecinovský VŠE – 03

41 Posluchač – implementace
Posluchač (pozorovatel, předplatitel) se musí přihlásit u vysílače (pozorovaného, vydavatele) Vysílač je ochoten přijmout přihlášku pouze od objektů implementujících rozhraní definující jak objektu oznámit, že došlo k očekávané události Posluchač se po přihlášení o událost dál nestará a hledí si svého Až vysílač zavolá dohodnutou metodu, pak zareaguje Událostmi řízené programování Copyright © 2006, Rudolf Pecinovský VŠE – 03

42 Příklad: Správce plátna
Kdo chce být zobrazován na plátně, musí se přihlásit u instance třídy SprávcePlátna Správce registruje pouze instance rozhraní IKreslený, tj. instance tříd, jež je implementují Kdykoliv se dozví, že se situace na plátně změnila, nechá jednoho po druhém překreslit Objekt předem neví, kdy bude pořádán, aby se překreslil Aby se objekty nemohly kreslit, kdy si vzpomenou, je plátno majetkem správce a je na ně možno kreslit pouze kreslítkem, které obdrží překreslovací metoda jako parametr Copyright © 2006, Rudolf Pecinovský VŠE – 03

43 Návrhový vzor Most Motivace Klasicky navržená kalkulačka
Kalkulačka po aplikaci vzoru Most Zisk z aplikace vzoru Testování sady programů

44 Most – motivace Klient komunikuje se třídou, která je pouze zprostředkovatelem (abstrakcí) nabízené služby; vlastní realizaci má na starosti jiná třída (implementace) Vložíme-li mezi abstrakci a implementaci rozhraní, oddělíme je a můžeme měnit jednu nezávisle na druhé S aplikací tohoto vzoru se setkáte (alespoň někteří) ve vaší první semestrální práci Copyright © 2006, Rudolf Pecinovský VŠE – 03

45 Klasicky navržená kalkulačka
Klasický přístup (viz skripta) Odděluje se návrh CPU and GUI; – Třídu GUI navrhuje vyučující – Třídu CPU navrhují studenti Stisk tlačítka z každé skupiny volá partnerskou metodu v CPU Třídy jsou těsně provázané což má své nepříjemné důsledky: S každou změnou definice CPU je třeba změnit definic GUI a naopak Každá verze studentského zadání vyžaduje vlastní verzi definice GUI Chceme-li po studentech, aby u zkoušky svoji třídu upravili, musíme příslušně upravit i námi definované GUI Uvedený přístup je nutný v případě neznají-li studenti rozhraní Copyright © 2006, Rudolf Pecinovský VŠE – 03

46 Po aplikaci vzoru Most Třída CPU implementuje rozhraní ICPU deklarující tři metody: RozměrKláves getRozměr() List<String> getPopisky() String stisknuto( String label ) Konstruktor třídy GUI Dostane instanci of CPU jako parametr Zeptá se jí na požadovaný rozměr klávesnice a seznam požadovaných popisků na tlačítcích Připraví GUI podle obdržených požadavků Běh programu: Instance GUI zjistí, jaké tlačítko bylo stisknuto a zašle instanci CPU zprávu s jeho popiskem Instance CPU zjistí, co stisk znamená, a vrátí GUI nový obsah displeje Copyright © 2006, Rudolf Pecinovský VŠE – 03

47 Co jsme tím získali GUI může spolupracovat s různými CPU; stačí, aby spolupracující CPU implementovala rozhraní ICPU Přiblížíme studentům význam a použití rozhraní Ukážeme, že tvůrce GUI nemusí znát spolupracující CPU předem, instance GUI se ji může dozvědět až při svém zrodu Můžeme do CPU svobodně přidávat další a další funkce, aniž bychom museli jakkoliv upravovat třídu GUI Můžeme připravit automatické testy Copyright © 2006, Rudolf Pecinovský VŠE – 03

48 Testování sady programů
Testovací třída se bude tvářit, že je zvláštní GUI Třída Verze dodá požadovanou sadu popisků spolu s testy definujícími požadované reakce na stisk kláves Rozhraní ICPU rozšíříme o metodu vracející pořadí řešeného zadání int getZadání() Můžeme přidat značkovací rozhraní IGUI, jež budou implementovat třídy, které se chtějí vydávat za GUI Copyright © 2006, Rudolf Pecinovský VŠE – 03

49 Dědičnost a dědění Princip 3 typy dědění
Implementace rozhraní jak realizace dědičnosti typů Dědění rozhraní Rozhraní s několika bezprostředními předky Princip dědičnosti implementace

50 Princip Mezi instancemi nějakého typu se často najde skupina instancí se společnými speciálními vlastnostmi Notebooky či sálové počítače jsou speciální druhy počítačů Psy, kočky, koně atd. jsou speciální druhy savců HTML dokumenty jsou speciálním druhem dokumentů OOP umožňuje definovat podtyp charakterizující tuto skupinu; pro značení obou typů používáme názvy: Podtyp – Nadtyp Předek – Potomek Základní – Odvozený typ Rodičovský – Dceřiný Instance potomka přebírají rozhraní svého rodiče – říkáme, že je zdědí Instance potomka jsou pouze speciální podmnožinou instancí rodiče, proto se mohou kdykoliv vydávat (alespoň formálně) za instance rodiče Copyright © 2006, Rudolf Pecinovský VŠE – 03

51 3 typy dědění 1/2 Dědění typů Dědění implementace Přirozené dědění
Potomek dodrží všechny vlastnosti a schopnosti předka, tj. převezme jeho signaturu a dodrží jeho kontrakt, a může se proto kdykoliv plnohodnotně vydávat za předka Příklad: třída implementující nějaké rozhraní Dědění implementace Potomek převezme od předka jeho implementaci, takže převzaté funkce nemusí definovat sám Příklad: Všechny třídy přebírají základní metody od třídy Object Nebezpečí: při přizpůsobování zděděných entit potřebám potomka není občas dodržen kontrakt předka Přirozené dědění Jak chápeme vztah obecný-speciální bez ohledu na programování Příklad: Čtverec je speciální druh obdélníku, ale nemůže se vydávat za obecný obdélník, protože namůže libovolně změnit velikost svých stran Copyright © 2006, Rudolf Pecinovský VŠE – 03

52 3 typy dědění 2/2 V dobře napsaném programu jsou všechny tři typy dědění v harmonii Je-li jeden aspekt použité dědičnosti v rozporu s ostatními, narušuje se stabilita programu a jeho rozšiřitelnost Při implementaci rozhraní a při jejich dědění se uplatní pouze dědění typů, protože interface žádnou implementaci nemá Dědění implementace svádí programátory k použití, které je v rozporu s děděním typů, a proto je vykládáme až po zvládnutí dědění typů Copyright © 2006, Rudolf Pecinovský VŠE – 03

53 Implementace rozhraní
Při implementaci rozhraní se implementující třída zavazuje implementovat všechny jím deklarované metody a dodržet jejich kontrakt Třída pak může vydávat svoje instance za instance daného rozhraní, tj. instance potomka se může vydávat za instanci předka Podmínkou správné funkce je dodržení kontraktu; ten ale překladač zkontrolovat nedokáže, takže je plně na bedrech programátora Opakování Copyright © 2006, Rudolf Pecinovský VŠE – 03

54 Dědění rozhraní Při dědění rozhraní potomek deklaruje, kdo je jeho předek V Javě smí interface deklarovat více předků současně public interface Potomek extends Předek1, Předek2 Potomek přebírá všechny deklarace všech předků a může přidat i svoje vlastní Třída implementující potomka implementuje každého z jeho předků => třída implementující rozhraní může svoji instanci vydávat nejenom za instanci daného rozhraní, ale také za instanci kteréhokoliv z jeho předků Copyright © 2006, Rudolf Pecinovský VŠE – 03

55 Použití dědění několika rozhraní
Metoda vyžaduje, aby její parametr implementoval dvě různá rozhraní Java neumožňuje deklarovat, že parametr je současné instancí dvou různých typů Tuto nemožnost lze obejít tak, že definujeme interface, který je potomkem obou rozhraní, a deklarujeme parametr jako instanci tohoto potomka Copyright © 2006, Rudolf Pecinovský VŠE – 03

56 Ukázka použití dědičnosti rozhraní
Copyright © 2006, Rudolf Pecinovský VŠE – 03

57 Ukázky definic public interface IKreslený {
public void nakresli( Kreslítko kreslítko ); } public interface IPosuvný extends IKreslený { public Pozice getPozice(); public void setPozice( Pozice pozice ); public void setPozice( int x, int y ); public interface INafukovací extends IKreslený { public Rozměr getRozměr(); public void setRozměr( Rozměr rozměr ); public void setRozměr( int šířka, int výška ); public interface IHýbací extends IPosuvný, INafukovací {} Copyright © 2006, Rudolf Pecinovský VŠE – 03

58 Rozhraní s více přímými předky
Má-li rozhraní několik rodičů, může se stát, že více z nich deklaruje metody se shodnou signaturou Zdědí-li potomek z několika stran metody se shodnou signaturou, musí mít všechny stejný kontrakt, protože Java je všechny považuje za deklaraci stejné metody Copyright © 2006, Rudolf Pecinovský VŠE – 03

59 Princip dědičnosti implementace
Dědičnost implementace je speciální případ skládání, při němž se „spolknutým“ objektem převezmu i jeho rozhraní Objekt, který je přebírán i s jeho rozhraním označujeme jako rodičovský podobjekt Metody a atributy rodičovského podobjektu označujeme jako zděděné Při obdržení zprávy (volání metody) z rodičovského rozhraní instance reaguje jedním ze dvou způsobů podle toho, zda má definovanou vlastní verzi příslušné metody: Má-li ji definovánu, zavolá ji Nemá-li ji definovánu, zavolá rodičovskou verzi Neexistuje způsob, jak zvenku zavolat rodičovskou verzi metody, která je překrytá verzí definovanou v dceřiné třídě Copyright © 2006, Rudolf Pecinovský VŠE – 03

60 Návrhový vzor Dekorátor

61 Motivace V knihovně potřebujeme nabízet třídy‘ poskytující různé kombinace funkcionalit Při nutnosti nabízet téměř všechny možné kombinace roste počet potřebných tříd kombinatoricky = neúnosně S každou další přidanou funkcionalitou musíme přidat násobek dosud existujících tříd S každou přidanou základní třídou musíme přidat i třídy pro možné kombinace přidaných funkcionalit Copyright © 2006, Rudolf Pecinovský VŠE – 03

62 Charakteristika Návrhový vzor Dekorátor umožňuje snížit kombinatoricky rostoucí počet tříd Každá dodaná funkčnost je implementována jako „ozdobení“ (dekorování) jiného objektu Dekorátor rozšiřuje (zdobí) objekt, ne třídu; na rozdíl od statické dědičnosti pracuje dynamicky Základní třídy i dekorátory mají společného rodiče Příklad Knihovna proudů java.io (s bufferem, řádkováním, daty, …) swing (pole, s posuvníkem, s okrajem, s oběma, …) Copyright © 2006, Rudolf Pecinovský VŠE – 03

63 Implementace 1/2 Zabalit objekt do objektu poskytujícího novou funkcionalitu, který tak původní objekt ozdobí (dekoruje) novou funkcionalitou Pro každou novou funkcionalitu pak bude stačit přidat pouze jedinou obalovou (dekorující) třídu Konstruktor dekorátoru přebírá dekorovaný objekt jako parametr a „obalí“ jej vlastními schopnostmi Dekorátor většinou přidává metody, které se starají o jím přidanou funkčnost. Může ale také pouze překrýt metody svých předků a definovat je pro daný účel efektivněji Požadavky nesouvisející s dodatečnou funkčností předá dekorátor dekorovanému objektu a vrátí obdržený výsledek Copyright © 2006, Rudolf Pecinovský VŠE – 03

64 Implementace 2/2 Přidávané funkcionality je možné kumulovat, tj. zabalený objekt lze znovu zabalit do objektu přidávajícího další funkcionalitu Výsledný objekt lze vytvářet postupně: IAuto benzin = new Benzin(); IAuto abs = new ABS( benzin ); AAuto auto = new Automat(abs); Nebo najednou AAuto auto1 = new Automat( new ABS(new Benzin()) ); AAuto auto2 = new Automat( new ABS( new Benzin()) ); Dekorátory mají někdy ještě vlastního rodiče se společnou implementací. Ten pak bývá koncipován jako adaptér nabízející implicitní funkčnost: delegování metod na obalený objekt a vracení obdržených výsledků Copyright © 2006, Rudolf Pecinovský VŠE – 03

65 Struktura tříd při implementaci vzoru Dekorátor
Dekorátor pracuje jako obálka kolem dekorovaného objektu zabezpečující dodatečnou funkčnost Občas bývá nazýván Wrapper Copyright © 2006, Rudolf Pecinovský VŠE – 03

66 Příklad – diagram tříd bez dekorátoru
Copyright © 2006, Rudolf Pecinovský VŠE – 03

67 Příklad – diagram tříd s dekorátorem
Copyright © 2006, Rudolf Pecinovský VŠE – 03

68 Příklad – ukázka implementace
public class Okružní implements IMultiposuvný { // ... Vynechané deklarace public Okružní(IPosuvný dekorovaný) { this.dekorovaný = dekorovaný; } @Override public Pozice getPozice() { return dekorovaný.getPozice(); public void setPozice(Pozice pozice) { dekorovaný.setPozice(pozice); public void přesunuto() { // Tělo metody přidávající funkčnost //...Další definované metody Copyright © 2006, Rudolf Pecinovský VŠE – 03

69 Třída Object a její metody

70 Třída Object Všechny objekty obsahují odkaz na rodičovský podobjekt, jenž je instancí třídy Object Všechny třídy přebírají rozhraní třídy Object, a mohou proto vydávat svoje instance za instance třídy Object Známe-li vlastní třídu dané instance, můžeme instanci vydávající se za instanci třídy Object přetypovat na instanci její mateřské třídy public class Pozice { public final int x, y; //... Vynechané metody public boolean equals( Object o ) { if( !(o instanceof Pozice) ) return false; Pozice p = (Pozice) o; return (x == p.x) && (y == p.y); } Copyright © 2006, Rudolf Pecinovský VŠE – 03

71 Rozhraní třídy Object public boolean equals(Object obj)
public int hashCode() public final Class<? extends Object> getClass() public String toString() protected void finalize() throws Throwable protected Object clone() throws CloneNotSupportedException public final void notify() public final void notifyAll() public final void wait() public final void wait(long timeout) public final void wait(long timeout, int nanos) throws InterruptedException Copyright © 2006, Rudolf Pecinovský VŠE – 03

72 Metody třídy Object v BlueJ
V BlueJ uvádějí objekty metody zděděné od třídy Object ve zvláštní nabídce Definuje-li metoda vlastní verzi, je v této nabídce uvedeno, že metoda je překrytá … a příslušný příkaz je zopakován v nabídce daného objektu Při zavolání překryté metody se zavolá dceřiná, překrývající metoda Copyright © 2006, Rudolf Pecinovský VŠE – 03

73 Metoda equals(Object)
public boolean equals(Object obj) Metoda musí umět porovnat objekt s jakýmkoliv jiným objektem Měla by být (pro běžné situace musí být): Reflexivní: a.equals(a) == true Symetrická: a.equals(b) == b.equals(a) Tranzitivní: a.equals(b) & b.equals(c) <= a.equals(c) Stabilní: co platí teď, musí platit pořád (proto musí být hodnotové objekty neměnné) Synchronizovaná s metodou hashCode() public class Pozice { public final int x, y; //... Vynechané metody public boolean equals( Object o ) { if( !(o instanceof Pozice) ) return false; Pozice p = (Pozice) o; return (x == p.x) && (y == p.y); } Copyright © 2006, Rudolf Pecinovský VŠE – 03

74 Metoda hashCode() public int hashCode()
Přiřazuje instanci celé číslo používané při ukládání instance do hešových tabulek Musí platit a.equals(b) => a.hashCode() == b.hashCode() Mělo by platit Hodnoty musí být co nejrovnoměrněji rozprostřeny Hodnota musí být spočtena dostatečně rychle Copyright © 2006, Rudolf Pecinovský VŠE – 03

75 Metoda getClass() public final Class<? extends Object> getClass() Metoda je konečná => není ji možné překrýt Metoda vrací class-objekt třídy dané instance; class-objekt třídy je instance třídy Class Class-objekt třídy Class je také instancí třídy Class Zjištění úplného názvu třídy instance iii: String s = iii.getClass().getName(); Zjištění vlastního názvu třídy (tj. bez balíčků) instance iii: String s = iii.getClass().getSimpleName(); Class-objekt třídy lze získat i jako literál: Třída.class Některé metody vyžadují class-objekt jako parametr Copyright © 2006, Rudolf Pecinovský VŠE – 03

76 Metoda toString() public String toString()
Vrací řetězcovou reprezentaci dané instance, tj. podobu instance převedené na textový řetězec Implicitní verze definovaná třídou Object vrací getClass().getName() + + Integer.toHexString(hashCode()) Metodu volá operátor sčítání při „sčítání“ instance s řetězcem a z toho plynoucímu převodu instance na textový řetězce, "" + objekt dá stejný výsledek jako objekt.toString() Metodu toString() by měla definovat každá třída Copyright © 2006, Rudolf Pecinovský VŠE – 03

77 Metoda finalize() protected void finalize() throws Throwable
Metodu volá uklizeč při odstraňování instance z haldy; metoda má za úkol „uklidit“ prostředky alokované instancí Nikdy není zaručeno, kdy se uklizeč (garbage collector) rozhodne instanci odstranit a dokonce ani to, zda ji do ukončení aplikace vůbec odstraní (může předat operačními systému nevyčištěnou paměť) Je to metoda posledního zoufalství, když neumíme úklid (např. zavření otevřených souborů) zařídit lépe Metodu lze využít pro kontrolu toho, zda program po instanci opravdu uklidil – objeví-li metoda neuklizené zbytky, znamená to chybu v programu Copyright © 2006, Rudolf Pecinovský VŠE – 03

78 Metoda clone() protected Object clone() throws CloneNotSupportedException Vytváří kopii daného objektu, pro níž by mělo platit: x.clone() != x x.clone().getClass() == x.getClass() x.clone().equals(x) Předchozí pravidla není nutné dodržet, ale k jejich nedodržení je třeba mít pádný důvod Implicitní implementace je dodržuje, navíc vyžaduje, aby třída implementovala rozhraní Cloneable v opačném případě vyhodí CloneNotSupportedException Copyright © 2006, Rudolf Pecinovský VŠE – 03

79 Rozhraní Cloneable Rozhraní Cloneable je „značkovací“ rozhraní, tj. rozhraní, které nevyžaduje implementaci žádné metody Implementací rozhraní se třída pouze zavazuje splnit kontrakt, jenž pouze vyžaduje, aby byla korektně implementována metoda clone(), a současně ostatním povoluje vytvářet kopie jejích instancí klonováním Překryvná verze metody clone() může pro vytvoření kopie volat konstruktor nebo využít rodičovské verze super.clone() (využití druhé možnosti je výrazně častější) Metoda clone() je chráněná (protected) ; chceme-li ji zveřejnit, stačí v řadě případů jednoduchá definice public Object clone() { return super.clone(); } Copyright © 2006, Rudolf Pecinovský VŠE – 03

80 Metody pro synchronizaci vláken
public final void notify() Oznamuje monitoru, že stav sdíleného prostředku se změnil public final void notifyAll() Jako předchozí, ale vzbudí se všechna čekající vlákna public final void wait() public final void wait(long timeout) public final void wait(long timeout, int nanos) throws InterruptedException Oznamuje monitoru, že čeká na změnu stavu daného prostředku; dobu čekání může omezit parametrem Všechny synchronizační metody jsou konečné a není je tedy možné překrýt Copyright © 2006, Rudolf Pecinovský VŠE – 03

81 Rudolf Pecinovský mail: rudolf@pecinovsky.cz ICQ: 158 156 600
Děkuji za pozornost Rudolf Pecinovský mail: ICQ:


Stáhnout ppt "Rudolf Pecinovský rudolf@pecinovsky.cz Rozhraní Rudolf Pecinovský rudolf@pecinovsky.cz."

Podobné prezentace


Reklamy Google