PB161 PB161 – Programování v jazyce C++ Objektově Orientované Programování Šablony, Návrhové principy a (anti-)vzory PB161 | Šablony, Návrhové principy.

Slides:



Advertisements
Podobné prezentace
Standardní knihovní funkce pro práci s textovými řetězci
Advertisements

ÚVOD DO C++ 3 TŘÍDY a objekty - POKRAČOVÁNÍ
Programování v C jazyku - SEMINÁŘ
ZŠ a MŠ Olšovec, příspěvková organizace Vzdělávací materiál, šablona – Inovace a zkvalitnění výuky směřující k rozvoji čtenářské a informační gramotnosti.
Škola Střední průmyslová škola Zlín
Úvod do objektového modelování
Jazyk C# a platforma .NET ZS 2013/2014
C++ Přednáška 1 Neobjektové rozšíření jazyka Základy vstupu a výstupu Ing. Jiří Kulhánek, kat. 352, VŠB TU Ostrava 2004.
Digitální výukový materiál zpracovaný v rámci projektu „EU peníze školám“ Projekt:CZ.1.07/1.5.00/ „SŠHL Frýdlant.moderní školy“ Škola:Střední škola.
Výukový materiál zpracovaný v rámci projektu EU Základní škola a mateřská škola Dvorce, okres Bruntál, příspěvková organizace Pořadové číslo projektu:
Pole, ukazatele a odkazy
BLIŽŠÍ POHLED NA TŘÍDY, DĚDIČNOST - úvod
Algoritmy I Cvičení č. 1.
Formy dějepisného vyučování Přednáška č. 7 ZS AR 2013/2014.
Programování v C++ cvičení Filip Zavoral.
Preprocess Úvod do tvorby funkcí Princip preprocesoringu Direktivy preprocesoru Podmíněný překlad Základy tvorby funkcí Zjednodušený popis principu předávaní.
C# pro začátečníky Mgr. Jaromír Osčádal
Sample Solutions CTU Open Contest 2012 Czech Technical University in Prague.
Programování v C++ Cvičení.
PROGRAMOVACÍ JAZYKY (c) Tralvex Yeap. All Rights Reserved.
1 Extreme programming v praxi Martin Junek, product manager
Sociální zabezpečení a důchodová politika SZDP Přednášející: Mgr. Hana Grzegorzová Typ předmětu: povinně volitelný, kontrola docházky…..nastaveny na první.
Seminář C++ 9. cvičení Šablony Ing. Jan Mikulka. Šablony ► template – vzory, podle kterých může překladač tvořit skupiny podobných tříd nebo funkcí, které.
ŠKOLA:Gymnázium, Tanvald, Školní 305, příspěvková organizace ČÍSLO PROJEKTU:CZ.1.07/1.5.00/ NÁZEV PROJEKTU:Šablony – Gymnázium Tanvald ČÍSLO ŠABLONY:III/2.
PŘEDNÁŠKA 0. Jiří Šebesta MRAR – Radiolokační a radionavigační systémy
PB161 Jmenné prostory, I/O proudy PB161 | Jmenné prostory, IO proudy PB161 – Programování v jazyce C++ Objektově Orientované Programování.
Seminář C cvičení STL, Trolltech Ing. Jan Mikulka.
PB161 – Programování v jazyce C++ Objektově Orientované Programování
Vaše první aplikace V rámci projektu „Cesta k vědě“ (veda.gymjs.net) vytvořil V. Pospíšil a Antonín Šulc. Modifikace a.
Úvod. školní: příprava na předmět Databázové systémy praktický: webové aplikace databázové systémy základy vývoje webových aplikací od návrhu databáze.
Dynamická alokace, polymorfismus
Výukový materiál byl zpracován v rámci projektu OPVK 1.5 EU peníze školám registrační číslo projektu:CZ.1.07/1.5.00/ Autor:Mgr. Stanislava Kubíčková.
Strategy. Strategy – „All-in-1“ na začátek class AStrategy { public: virtual void Algorithm()=0; protected: AStrategy(); }; class SpecificStrategy: public.
PB161 – Programování v jazyce C++ Objektově Orientované Programování
POŽADAVKY NA ZÁPOČET Z MAEK1 Ing. Martina Hedvičáková, Ph.D.
Seminář C++ 4. cvičení Objekty Ing. Jan Mikulka. Co je objekt ► obraz třídy i instance ► třída – definovaná za pomocí klíčového slova class ► instance.
6. cvičení Polymorfismus
PB161 Právo friend, přetěžování operátorů, přetypování PB161 | Friend, operátory PB161 – Programování v jazyce C++ Objektově Orientované Programování.
KIV/PPA2 1.cvičení Cvičící: Pavel Bžoch.
Číslo šablony: III/2 VY_32_INOVACE_P4_3.8 Tematická oblast: Aplikační software pro práci s informacemi II. Databáze – základy SQL Typ: DUM - kombinovaný.
OSNOVA: a) Úvod do OOPb) Třídy bez metod c) Třídy s metodamid) Konstruktory a destruktory e) Metody constf) Knihovní třídy g) Třídy ve tříděh) Přetížení.
Název projektu: Šablony Špičák číslo projektu: CZ.1.07/1.4.00/ šablona III/2 autor výukového materiálu: Mgr. Jana Jiroušová, VM vytvořen: květen.
Bakalářská práce - zpracování
C# - předávání parametrů Centrum pro virtuální a moderní metody a formy vzdělávání na Obchodní akademii T.G. Masaryka, Kostelec nad Orlicí.
IB111 Programování a algoritmizace
Posloupnosti a jejich vlastnosti (4.část)
OSNOVA: a) Přetížení členských funkcí b) Dědičnost tříd Jiří Šebesta Ústav radioelektroniky, FEKT VUT v Brně Počítače a programování 2 pro obor EST BPC2E.
Modulární systém dalšího vzdělávání pedagogických pracovníků JmK v přírodních vědách a informatice CZ.1.07/1.3.10/ Grafové pojmy Projekt učitelé.
Cvičení Filip Zavoral.  Docházka ◦ aktivní účast, znalost předchozí látky ◦ 3 nepřítomnosti OK, déledobější domluvit předem  DÚ ◦ uprostřed semestru.
OSNOVA: a) Příkazy pro cykly II. b) Příkazy pro řízení přenosu c) Příkazy – příklad d) Řetězce v C e) Funkce “stdio.h“ pro řetězce f) Funkce “string.h“
OSNOVA: a)Funkce – úvod b) Hlavičky funkcí c) Rekurze funkcí d)Knihovny funkcí e)Příklady Jiří Šebesta Ústav radioelektroniky, FEKT VUT v Brně Počítače.
CHARLES UNIVERSITY IN PRAGUE faculty of mathematics and physics Advanced.NET Programming I + II 1 st Lecture Pavel Ježek.
KIV/PRJ Speciální předmět pro zvídavé a hravé.
PPA1 – 5.cvičení Pavel Bžoch.
STRING A UKAZATELE. Co to je řetězec? Řetězec v Javě je samostatný objekt. Je konstantní, co znamená, že jednou vytvořený řetězec nelze změnit. Chceme-li.
Office I. Miroslav Lorenc.
C – jak na procedury Mgr. Lenka Švancarová. C – procedury #include int main() { printf("Ahoj\n"); return(0); } #include void pozdrav(void) { printf("Ahoj\n");
Geometrická posloupnost (1.část)
OSNOVA: a) Algoritmy třídění b) Třídění dynamických záznamů Jiří Šebesta Ústav radioelektroniky, FEKT VUT v Brně Počítače a programování 1 pro obor EST.
KIV/PPA2 1.cvičení Cvičící: Pavel Bžoch. Údaje o cvičícím Pavel Bžoch Kancelář: UL408 Konzultační hodiny: –Středa 12:05 – 12:50 –Čtvrtek 11:10 – 11:55.
CHARLES UNIVERSITY IN PRAGUE faculty of mathematics and physics Jazyk C# a platforma.NET ZS 2015/2016 Pavel Ježek
EU peníze středním školám Název vzdělávacího materiálu: Roztoky – výpočet koncentrace II, ředění Číslo vzdělávacího materiálu: ICT9/12 Šablona: III/2 Inovace.
1 Dopravní simulace Lekce 1:Úvod. 2 Představení Ondřej Přibyl, Ph.D. Schůzky: Konzultační hodiny: dohodou.
Počítače a programování 2
Advanced .NET Programming II 1st Lecture
Číslo projektu školy CZ.1.07/1.5.00/
NÁZEV ŠKOLY: Střední odborná škola Net Office, spol. s r. o
PŘEVODY JEDNOTEK ČASU 60 minut 60 sekund 1 hodina 1 minuta 1 h 1 min
Rozvoj IT kompetencí Pavla Kovářová.
Transkript prezentace:

PB161 PB161 – Programování v jazyce C++ Objektově Orientované Programování Šablony, Návrhové principy a (anti-)vzory PB161 | Šablony, Návrhové principy a vzory,

PB161 Organizační Zápočtový příklad nanečisto ●na vašem cvičení, týden od nácvik, od naostro Zvané přednášky Jiří Weiser (Laboratoř Paradise) ●C Juraj Michálek (YSoft) ●C++ in large scale projects PB161 | Šablony, Návrhové principy a vzory,

PB161 Hint pro domácí úkol Většina „téměř“ správných řešení neprojde časovým limitem u velkého grafu Časové omezení pro dobu běhu je 20 sekund ●Řešení od J. Weisera vytvořené za 1 hodinu zpracuje velký graf z testů naostro za 0,3 s Hint: graf má velké množství uzlů – dotaz na existenci hrany může být pomalý – lze optimalizovat PB161 | Šablony, Návrhové principy a vzory,

PB161 Šablony PB161 | Šablony, Návrhové principy a vzory,

PB161 Šablony funkcí - motivace Máme kód, který chceme použít s hodnotami různých typů ●např. prohoď hodnoty dvou argumentů A a B Kód (tělo funkce) je pro různé typy hodnot shodný ● temp = A; A = B; B = temp; ●liší se právě jen typem používaných hodnot Musíme vytvářet pro každý typ samostatnou funkci? Nemusíme, známe přece makra! PB161 | Šablony, Návrhové principy a vzory,

PB161 Přehazování prvků – využití makra PB161 | Šablony, Návrhové principy a vzory, #include using std::cout; using std::endl; #define MYSWAP(A,B) {\ A = A + B;\ B = A - B;\ A = A - B;} int main() { float af = 5; float bf = 7; // Swap two by macro... cout << af << " " << bf << endl; MYSWAP(af, bf); cout << af << " " << bf << endl; return 0; } #include using std::cout; using std::endl; void myswap(int& a, int& b) { int temp = a; a = b; b = temp; } void myswap(float& a, float& b) { float temp = a; a = b; b = temp; } int main() { // Swap two integers int a = 5; int b = 7; cout << a << " " << b << endl; myswap(a, b); cout << a << " " << b << endl; return 0; }

PB161 Přehazování prvků – problémy s makrem Nejasné chybové hlášky při syntaktické chybě ●nevidíme přesně řádek chyby Makra nejsou typově bezpečná Nelze krokovat debuggerem Často obtížně odhalitelná logická chyba ●nevidíme kód po rozvinutí makra Často spoléháme na existenci některých operátorů ●např. + a – u SWAP ●nemůžeme využít dodatečnou proměnnou temp = Šablony funkcí výše uvedené problémy řeší PB161 | Šablony, Návrhové principy a vzory,

PB161 Šablony funkcí - ukázka PB161 | Šablony, Návrhové principy a vzory, void myswap(int& a, int& b) { int temp = a; a = b; b = temp; } void myswap(string& a, string& b) { string temp = a; a = b; b = temp; } void myswap(T& a, T& b) { T temp = a; a = b; b = temp; } template void myswap(T& a, T& b) { T temp = a; a = b; b = temp; } Zatím nelze zkompilovat, typ T není známý std::string as = "Hello"; std::string bs = "World"; myswap (as, bs); myswap (ai, bi); Klíčovým slovem template zavedeme šablonu Do <> uvádíme datový typ nahrazující T při potřebě využití v kódu Klíčovým slovem typename nebo class označíme parametrizovatelný typ

PB161 Šablony funkcí – základní vlastnosti Jsou to vlastně „vylepšená“ makra Rozvíjí se do kódu stejně jako makra ●mluvíme o tzv. instanci šablon ● myswap (ai, bi); ●instanci šablon už znáte z STL kontejnerů ● vector myVect; Instance je vytvářena během překladu ●výsledek je rychlý ●samotná šablona v přeloženém kódu není ●nepoužité šablony (== bez instance) v přeloženém kódu vůbec nejsou ●kód funkce je většinou vkládán do kódu (inline) PB161 | Šablony, Návrhové principy a vzory,

PB161 Šablony funkcí - ukázka 10 template void myswap(T& a, T& b) { T temp = a; a = b; b = temp; } std::string as = "Hello"; std::string bs = "World"; myswap (as, bs); myswap (ai, bi); PB161 | Šablony, Návrhové principy a vzory,

PB161 Šablony funkcí – více typů parametrů Šablona může mít víc parametrů pro typ Můžeme využít i pro funkci bez parametrů nebo parametrizovat návratovou hodnotu ● T foo() { … } PB161 | Šablony, Návrhové principy a vzory, template void myswap(T& a, T& b, U& c, U& d) { T temp1 = a; a = b; b = temp1; U temp2 = c; c = d; d = temp2; } // Swap two integers and two strings by template function int main() { int ai = 5; int bi = 7; std::string as = "Hello"; std::string bs = "Happy"; myswap (ai, bi, as, bs); return 0; }

PB161 Šablony funkcí - přetěžování Můžeme přetěžovat stejně jako běžné funkce PB161 | Šablony, Návrhové principy a vzory, #include using std::cout; using std::endl; template void myswap(T& a, T& b) { T temp = a; a = b; b = temp; } template void myswap(T& a, T& b, T& c) { T temp = a; a = b; b = c; c = temp; } int main() { std::string as = "Hello"; std::string bs = "Happy"; std::string cs = "World"; // Swap two strings by template function cout << as << " " << bs << endl; myswap (as, bs); cout << as << " " << bs << endl; // Swap three strings by template function cout << as << " " << bs << " " << cs << endl; myswap (as, bs, cs); cout << as << " " << bs << " " << cs << endl; return 0; }

PB161 Šablony funkcí – priority volání U instance šablon nemusíme uvádět typ, pokud bude jednoznačně určitelná cílová šablona ● myswap (as, bs); místo myswap (as, bs); Co v případě, že existuje i běžná funkce pro tento typ? ●tj. funkce void myswap(string&,string&) {} Priority volání 1.Existuje-li pro daný typ parametrů funkce, použije se 2.Neexistuje-li, hledá se šablona pro daný typ 3.Neexistuje-li, chyba při překladu Nekombinujte ale přetěžování funkcí a šablonové specializace zároveň (riziko chyby a neočekávaného chování) PB161 | Šablony, Návrhové principy a vzory,

PB161 Šablony tříd Šablona pro vytváření tříd parametrizovaných konkrétním datovým typem Např. položka dynamického seznamu nese hodnotu konkrétního typu PB161 | Šablony, Návrhové principy a vzory, class CLinkedItem { CLinkedItem* m_pNextItem; CLinkedItem* m_pPrevItem; int m_value; … }; template class CLinkedItem { CLinkedItem* m_pNextItem; CLinkedItem* m_pPrevItem; T m_value; public: CLinkedItem(T value) : m_pNextItem(0), m_pPrevItem(0), m_value(value) {} void setValue(T value) { m_value = value;} T getValue() { return m_value;} };

PB161 Šablony tříd – ukázka PB161 | Šablony, Návrhové principy a vzory, template class CLinkedItem { CLinkedItem* m_pNextItem; CLinkedItem* m_pPrevItem; T m_value; public: CLinkedItem(T value) : m_pNextItem(0), m_pPrevItem(0), m_value(value) {} void setValue(T value) { m_value = value;} T getValue() { return m_value;} }; #include using std::cout; using std::endl; int main() { CLinkedItem linkInt(10); CLinkedItem linkString("Hello world"); cout << linkInt.getValue() << endl; cout << linkString.getValue() << endl; return 0; }

PB161 Šablony tříd - implementace metody třídy Bez problémů, pokud implementujeme metodu zároveň s deklarací ●viz. předchozí příklad Pokud implementujeme mimo deklaraci třídy ●implementace metody u šablony třídy je také šablona ●použijeme syntaxi známou ze šablony funkce ●v případě implementace v rámci stejného *.h souboru jako deklarace šablony třídy bez problémů Umístění implementace metody třídy do separátního souboru (*.cpp) ●(běžný způsob pro nešablonové třídy a metody) ●u šablonových metod typicky problematické ●překladač „nevidí“ zároveň šablonu třídy a metody ●preferujte umístění implementace šablonových funkcí/tříd do *.h ● PB161 | Šablony, Návrhové principy a vzory,

PB161 Šablona metod třídy – ukázka PB161 | Šablony, Návrhové principy a vzory, template class CLinkedItem { public: // … void setValue(T value); }; template void CLinkedItem ::setValue(T value) { m_value = value; } class CLinkedItem { public: // … void setValue(int value); }; void CLinkedItem::setValue(int value) { m_value = value; } Nyní máme šablonu s typem T I metoda třídy je šablona s typem T A jmenný prostor CLinkedItem je šablona s typem T

PB161 Šablony tříd – částečná specializace Šablonou vytváříme obecnou implementaci pro všechny vhodné datové typy ●např. CLinkedItem očekává od typu pouze operátor = Specializace šablony nám umožňuje tuto obecnou implementaci pro konkrétní typ změnit ●např. CLinkedItem se strcpy namísto operátoru = pro typ char* Částečná specializace šablon ●upřesníme podmnožinu typů ●typické použití pro ukazatele ● template class CLinkedItem … Pokud vytváříme instanci s ukazatelovým typem, bude mít šablona CLinkedItem přednost před CLinkedItem PB161 | Šablony, Návrhové principy a vzory,

PB161 Šablony tříd – úplná specializace Úplná specializace šablon zafixuje konkrétní typ např. char* template <> class CLinkedItem { Programátor nemusí uvést typ ● např. využito u std::string ( typedef basic_string string; ) Při překladu se použije nejspecializovanější šablona stejně jako pro šablony funkcí char* vs. T* vs. T (sestupná priorita) Specializace šablon tříd nesouvisí s dědičností jde o samostatnou třídu bez dědického vztahu k obecnější PB161 | Šablony, Návrhové principy a vzory,

PB161 Úplná specializace - ukázka PB161 | Šablony, Návrhové principy a vzory, // Full specialization for char* type template <> class CLinkedItem { CLinkedItem* m_pNextItem; CLinkedItem* m_pPrevItem; char* m_value; public: CLinkedItem(char* value) : m_pNextItem(0), m_pPrevItem(0) { m_value = 0; setValue(value); } void setValue(char* value); const char* getValue() const { return m_value;} ~CLinkedItem() { if (m_value) delete[] m_value; } }; void CLinkedItem ::setValue(char* value) { if (m_value) delete[] m_value; m_value = new char[strlen(value) + 1]; strncpy(m_value, value, strlen(value)+1); } Šablona není parametrizovaná žádným volitelným datovým typem Analogie static inline Typ šablony je zafixován na char* Jmenný prostor CLinkedItem použijeme ve specializaci s char*

PB161 Ukázka ze cvičení PB161 | Šablony, Návrhové principy a vzory, // Set for Geometry2D objects class ObjectSet : public Geometry2D { std::vector objects; ObjectSet(const ObjectSet &o) { // copy all items from objects vector } ObjectSet& operator=( ObjectSet o ) { myswap(o); return *this; } // custom swap function calls swaps for vectors (objects) void myswap(ObjectSet& o) { std::swap(objects, o.objects); } }; // Create specialization of std::swap function for whole ObjectSet namespace std { template<> inline void swap(ObjectSet& lhs, ObjectSet& rhs) { lhs.myswap(rhs); } } Operátor = provede copy & swap idiom (příjme hodnotou, swap všech potřebných položek v myswap() ) myswap() volá existující implementaci std::swap pro své atributy, zde pro std::vector Vytvoříme úplnou specializaci std::swap pro naši třídu ObjectsSet – použito v případě, že někdo chce dělat copy&swap s naší třídou ObjectSet set1; ObjectSet set2; set2 = set1; std::swap(set1, set2);

PB161 Výhody šablon Přehledný kód s typovou kontrolou ●stejně jako běžná funkce/třída ●pouze doplníme parametrizaci datovým typem Je rozvinuto přímo do kódu => rychlost Nepoužité šablony nejsou zahrnuty do kódu Typicky můžeme krokovat debuggerem ●můžeme hledat snáze logické chyby Plnohodnotná náhrada maker s výhodami Neutečete jim – STL == Standard Template Library PB161 | Šablony, Návrhové principy a vzory,

PB161 Návrhové principy PB161 | Šablony, Návrhové principy a vzory,

PB161 Jak navrhnout správně OO hierarchii? Co umístit do jedné třídy? Jaké třídy vytvořit a jaký mají mít mezi sebou vztah? Zapouzdření, dědičnost… jsou jen nástroje ●dobrý objektový návrh je schopnost je dobře použít PB161 | Šablony, Návrhové principy a vzory,

PB161 Jak se pozná špatný návrh? 1.I malá změna vyžaduje velké množství úprav v existujícím kódu 2.Změna způsobuje nečekané problémy v jiných částech kódu 3.Je příliš svázán s konkrétní aplikací ●je obtížné podčást kódu použít jinde Společným (negativním) prvkem je velká provázanost kódu ●OOP se snaží kód rozdělit do samostatných částí PB161 | Šablony, Návrhové principy a vzory,

PB161 Principy pro návrh OO architektury Pro OOP existuje 5 základních principů (a řada dalších) SRP - The Single Responsibility Principle OCP - The Open Closed Principle LSP - The Liskov Substitution Principle ISP - The Interface Segregation Principle DIP - The Dependency Inversion Principle (jednotlivé principy se někdy částečně překrývají) Postup 1.Porozumějte principům a s jejich vědomím navrhněte hierarchii 2.Zkontrolujte, zda principy nejsou porušeny a případně opravte PB161 | Šablony, Návrhové principy a vzory,

PB161 SRP - The Single Responsibility Principle Cílem je podpořit robustní rozšiřovatelnost aplikace Třída by měla být zodpovědná za plnění jediného funkčního požadavku ●při změně požadavků na aplikaci by důvod pro změnu konkrétní třídy měl být právě jeden ●při změně požadavků není zasažena nesouvisející funkčnost třídy (protože žádná další není ) s/srp.pdf s/srp.pdf PB161 | Šablony, Návrhové principy a vzory,

PB161 SRP – negativní ukázka PB161 | Šablony, Návrhové principy a vzory, Musíme i pro Geometry App vkládat kód GUI Při změně požadavků Graphical App musíme překompilovat Geometry App 28

PB161 SRP – problémy při porušení Porušení principu může vést k ●při použití jen jedné plněné funkčnosti se musí zbytečně kompilovat ostatní kód ●při úpravě kódu přestane fungovat jiná plněná funkčnost třídy PB161 | Šablony, Návrhové principy a vzory,

PB161 SRP – pozitivní ukázka PB161 | Šablony, Návrhové principy a vzory, Třída Rectangle využívá Geometric Rectangle pro výpočet plochy area() 30

PB161 OCP - The Open Closed Principle Klíčový princip pro využití abstrakce a polymorfismu Třída X by měla být navržena tak, aby: ●umožnila snadnou modifikaci své funkčnosti vytvořením nového potomka Y v reakci na nové požadavky (Open) ●pro výše uvedené nebylo nutné měnit kód třídy X (Closed) Dosahuje se pomocí abstrakce ●objekty mají metody navržené pro manipulaci s abstraktními třídami, nikoli konkrétními implementacemi ●lze tedy přidat nového potomka abstraktní třídy bez změny původního kódu PB161 | Šablony, Návrhové principy a vzory,

PB161 OCP – negativní ukázka PB161 | Šablony, Návrhové principy a vzory, Třída Client používá konkrétní třídu Server Nelze použít jinou třídu ServerX bez změny kódu třídy Client 32

PB161 OCP - The Open Closed Principle (2) Porušení principu může vést k ●změna požadavku vede ke kaskádě změn v kódu ●přidání nového typy objektu vyžaduje změnu stávajících Obecně nelze vždy zajistit 100% část principu týkající se uzavřenosti ●je potřeba dobře vybrat typ změn požadavků, vůči kterým design uzavře (tzv. strategické uzavření) ●a tyto požadavky vhodně abstrahovat PB161 | Šablony, Návrhové principy a vzory,

PB161 OCP – pozitivní ukázka PB161 | Šablony, Návrhové principy a vzory, Client využívá třídu Abstract Server Konkrétní implementace Server je potomek Abs. Server Dalším dobrým příkladem je istream a ostream z STL 34

PB int main() { IPrinter* printer = GetSelectedPrinter(); printer->PrintDocument(); printer->GetPendingDocuments(); return 0; } IPrinter* GetSelectedPrinter() { // user selects printer via GUI // e.g., InkPrinter -> selectedPrinter // e.g., LaserPrinter -> selectedPrinter return selectedPrinter; } Nový kód Existující kód PB161 | Šablony, Návrhové principy a vzory,

PB161 LSP - The Liskov Substitution Principle Pokud třída X používá ukazatel nebo referenci na základní třídu B, pak musí být schopná pracovat beze změny i s potomky třídy B ●aplikace může nahradit v instanci třídu B za její potomky a X tím nesmí být dotčená ●princip se týká i potomků třídy B ●nesmí očekávat víc, než nabízí předek B Souvisí úzce s OCP ●pokud aplikace splňuje OCP, tak by měla splňovat i LSP ●porušení LSP způsobí problémy s dodržením OCP PB161 | Šablony, Návrhové principy a vzory,

PB161 LSP - The Liskov Substitution Principle (2) Někdy označováno jako „Design by contract“ Dosahuje se pomocí dědičnosti, přetížení a vhodného návrhu Porušení principu může vést ke ●kaskádě změn v kódu při přidání nové třídy ●chybnému chování aplikace, protože X předpokládá něco o B, co je v potomcích B porušeno PB161 | Šablony, Návrhové principy a vzory,

PB161 LSP – negativní ukázka PB161 | Šablony, Návrhové principy a vzory, #include class Shape {}; class Circle : public Shape {}; class Square : public Shape {}; class GraphicScene { public: void DrawShape(Shape& s) { if (typeid(s) == typeid(Square)) DrawSquare(dynamic_cast (s)); else if (typeid(s) == typeid(Circle)) DrawCircle(dynamic_cast (s)); } void DrawSquare(Square& s) { // draw square } void DrawCircle(Circle& s) { // draw circle } }; GraphicScene umí pracovat s objekty typu Shape, ale musí si zjistit pro vykreslení jejich reálný typ Přidání nového potomka třídy Shape znamená nutnost úpravy i třídy DrawScene

PB161 LSP – pozitivní ukázka PB161 | Šablony, Návrhové principy a vzory, class Shape { public: virtual void Draw() const = 0; }; class Circle : public Shape { public: virtual void Draw() { // draw circle } }; class Square : public Shape { public: virtual void Draw() { // draw square } }; class GraphicScene { public: void DrawShape(Shape& s) { s.Draw(); } }; GraphicScene umí pracovat i s potomky třídy Scene, aniž by byly tyto známy v době psaní GraphicScene Potomci třídy Shape by neměli měnit očekávané chování slíbené na úrovni třídy Shape (např. by neměli začít něco načítat z cin )

PB161 ISP - The Interface Segregation Principle Navazuje na DIP a postihuje problém příliš velkých rozhraní ●takových, kde klientský objekt reálně využívá pouze malou podčást metod, ale je nucen záviset na všech ●při změně v nevyužívaných částech nutná rekompilace i klienta Klientské objekty by neměly být nuceni záviset na rozhraních, které nepoužívají Dosahuje se vytvářením více rozhraní PB161 | Šablony, Návrhové principy a vzory,

PB161 ISP - The Interface Segregation Principle Zkontrolujte třídy, jejichž rozhraní má mnoho metod Udělejte si seznam tříd, které toto rozhraní využívají ●opravdu používá třída A všechny metody? Oddělte metody pro A do samostatného rozhraní Např. postupem času vznikne třída s metodami umožňujícími ●přijímat zprávy (využívá jiný objekt typu producent) ●odesílat zprávy (využívá jiný objekt typu konzument) ●zobrazovat zprávy (využívá jiný objekt typu UI) Lze rozdělit alespoň do 3 separátních rozhranní ●např. konzument používá pouze rozhraní produkující zprávy PB161 | Šablony, Návrhové principy a vzory,

PB161 DIP - The Dependency Inversion Je výsledkem kombinace OCP a LSP Třída by měla být závislá na třídách s obdobnou nebo větší úrovní abstrakce ●pokud obecná třída závisí na specializované třídě, je obtížné ji použít pro jiný účel ●abstrakce by neměla záviset na detailech, ale naopak Dosahuje se využitím rozhraní ●v C++ čistě abstraktními třídami PB161 | Šablony, Návrhové principy a vzory,

PB161 DIP - The Dependency Inversion (2) Porušení principu může vést ke ●k nutnosti změny v obecné třídě pro přidání podpory nového typu ●snížené flexibilitě obecné třídy – použitelná jen pro to, s čím byla původně implementována PB161 | Šablony, Návrhové principy a vzory,

PB161 DIP – negativní ukázka PB161 | Šablony, Návrhové principy a vzory, Obecný algoritmus kopírování závisí na konkrétní implementaci printer nebo disk Změna výstupního zařízení (disk) vede ke změně Copy 44 void Copy() { int c; while ((c = ReadKeyboard()) != EOF) WritePrinter(c); } enum OutputDevice {printer, disk}; void Copy(outputDevice dev) { int c; while ((c = ReadKeyboard()) != EOF) if (dev == printer) WritePrinter(c); else WriteDisk(c); }

PB161 DIP – pozitivní ukázka PB161 | Šablony, Návrhové principy a vzory, Obdobně funguje např. STL copy algoritmus ●std::copy(istream_iterator,istream_iterator,ostream_iterator); 45 class Reader { public: virtual int Read() = 0; }; class Writer { public: virtual void Write(char) = 0; }; void Copy(Reader& r, Writer& w) { int c; while((c=r.Read()) != EOF) w.Write(c); }

PB161 KISS – Keep It Simple, Stupid! Jednoduché, postačující řešení může být lepší než designově rafinované, ale komplikované ●menší riziko chyby v tom, co snáze chápeme ●snažší pochopení od dalších vývojářů Je nutné hledat kompromis mezi aktuálními a budoucími požadavky ●předpoklad budoucích požadavků návrh typicky komplikuje ●přílišné omezení návrhu na aktuální požadavky typicky komplikuje budoucí rozšiřitelnost Snažte se průběžně validovat svůj návrh vůči požadavkům a nebojte se refaktorizace PB161 | Šablony, Návrhové principy a vzory,

PB161 Návrhové vzory PB161 | Šablony, Návrhové principy a vzory,

PB161 Návrhové vzory - motivace Většina programátorských problémů není nová a způsob jejich řešení se opakuje konkrétní implementace jsou lepší a horší postupem vykrystalizovaly vhodné konstrukce pro jejich řešení Označováno souhrnným pojmem návrhové vzory není vůbec omezeno pouze na C++ většinou jde o jazykově nezávislé konstrukce Termín vešel v širokou známost díky knize Design Patterns: Elements of Reusable Object- Oriented Software, Erich Gamma, Richard Helm, Ralph Johnson a John Vlissides (1994) podle čtyř autorů označováno často jako Gang of Four (GoF) PB161 | Šablony, Návrhové principy a vzory,

PB161 Návrhové vzory – jak začít? GoF kniha popisuje 23 návrhových vzorů GoF kniha není organizována z hlediska výuky ●neřadí od nejsnazších pro nejobtížnější ●neřadí ani od nejčastějších po nejobskurnější Použijeme jiné řazení a omezíme se pouze na vybrané vzory ● Detailní popis všech vzorů včetně zdrojáků ● ● PB161 | Šablony, Návrhové principy a vzory,

PB161 Návrhové vzory Co považovat za návrhový vzor? ●principiálně jednoduchý způsob, jak řešit skupiny podobných problémů ●důležitá je opakovatelnost použití dané konstrukce Pozitiva návrhových vzorů ●existující způsob řešení běžných problémů ●snížení množství nutných změn později v kódu ●zřejmě opravdu reálně zlepšují kód a jeho udržovatelnost ● Kritika návrhových vzorů ●návrhové vzory mohou být zbytečně složité na jednoduché problémy ●potřeba návrhových vzorů může vznikat z nedokonalosti použitého programovacího jazyka ● PB161 | Šablony, Návrhové principy a vzory,

PB161 Formát popisu jednotlivých vzorů Popis každého vzoru je dělen do těchto částí: 1.Záměr (Intent) shrnutí účelu použití a přínosu 2.Řešený problém (Problem) shrnutí problému, které je vzorem řešen 3.Discussion co má vzor za cíl a co naopak nemá 4.Structure technický popis realizace vzoru 5.Check list jak postupovat při implementaci konkrétního vzoru 6.Rules of thumb ověřená pravidla, která je vhodné dodržovat uvedení vzoru do kontextu s dalšími vzory (velice přínosné) PB161 | Šablony, Návrhové principy a vzory,

PB161 Demo: Návrhový vzor ‘Adapter’ - proč Máme existující komponentu A s nekompatibilním rozhraním pro použití jinou naší komponentou B ●nenabízí metody ve správném formátu (např. jako operátory) ●má jinou filozofii použití (např. předpokládá předalokovanou paměť) ●A ani B nechceme/nemůžeme měnit PB161 | Šablony, Návrhové principy a vzory,

PB161 Adapter – jak? Vytvoříme novou komponentu, která poskytuje rozhraní kompatibilní pro naše použití Metody komponenty adapteru volají metody původní komponenty a případně upravují chování např. tvorba operátoru + a jeho mapování na existující metody add() např. alokace potřebné paměti před voláním původních metod Implementováno pomocí dědičnosti pokud je rozhraní stejné, potřebujeme jen upravit vnitřní funkčnost Nebo agregace pokud měníme rozhraní PB161 | Šablony, Návrhové principy a vzory,

PB161 Návrhové vzory – jak dál Projděte si materiály na webu ● ● ●a další Přečtete si knihy ●Design Patterns: Elements of Reusable Object-Oriented Software a další Rozmyslete před další implementací, zda se některý vzor nehodí ● Seznamte se s knihovnami, které vzory využívají ●např. ACE PB161 | Šablony, Návrhové principy a vzory,

PB161 Návrhové anti-vzory PB161 | Šablony, Návrhové principy a vzory,

PB161 PB161 | Šablony, Návrhové principy a vzory, if(server.is_file_in_database(path)){ server.set_licence_data_from_database(path); char type; char constrain; bool right_input = false; permissions new_permissions = {{FULLY, 0, {0,0,0}}, {FULLY, 0, {0,0,0}}, {FULLY, 0, {0,0,0}}, {FULLY, 0, {0,0,0}}}; do{ cout<<endl<<"Enter type of file (t)text/(m)music/(e)executable: "; cin>>type; switch (type){ case 't': right_input = true; // display cout<<"Enter constrain for display (n)no/(p)partially/f(fully): "; cin>>constrain; switch (constrain){ case 'n': new_permissions.display.constricted = NO; new_permissions.display.count = -1; new_permissions.display.interval.year = -1; break; case 'p': int count; new_permissions.display.constricted = PARTIALLY; cout<<"Count of display (-1 for not set): "; cin>>count; if(count > -1){ new_permissions.display.count = count; } else{ new_permissions.display.count = -1; } int year, month, day; cout<<"Enter year (-1 for not set): "; cin>>year; if(year > -1){ new_permissions.display.interval.year = year; cout<<"Enter month: "; cin>>month; new_permissions.display.interval.month = month; cout<<"Enter day: "; cin>>day; new_permissions.display.interval.day = day; } else{ new_permissions.display.interval.year = -1; } break; case 'f': //f is default value break; default: cerr<<"Wrong input type. Please insert n/p/f."<<endl; right_input = false; break;

PB161 Návrhové antivzory (antipatterns) Typické konstrukce, jejichž výskyt signalizuje (budoucí) problémy ● Mohou vznikat nevhodným návrhem Mohou vznikat i postupně s rostoucím projektem Je dobré je znát a rozpoznat jejich výskyt ●a umět odstranit PB161 | Šablony, Návrhové principy a vzory,

PB161 Návrhový antivzor – špagetový kód Vzniká velice často a snadno ●vyznačuje se rozsáhlým kódem v jediné funkci ●vyznačuje se častým opakováním kódem s minimální změnou (pokud vůbec) ●vyznačuje se dlouhou řadou vnořených podmínek A určitě jej nelze vzít a použít jinde Pomůže pravidelný Refactoring ●opakované části kódu přesouváme do nové funkce ●dlouhý kód rozdělujeme do více funkcí ●…●… ● PB161 | Šablony, Návrhové principy a vzory,

PB161 Shrnutí Šablony umožňují typově nezávislé programování ●snažší na pochopení, než např. OOP ●pokud používáte často makra, naučte se i šablony Návrhové principy a vzory ●časem prověřené postupy, které vám mohou ušetřit práci při rozšiřování programu ●seznamte se s nimi a kontrolujte porušení v kódu PB161 | Šablony, Návrhové principy a vzory,

PB161 Bonus PB161 | Šablony, Návrhové principy a vzory,

PB161 Kdy přepisovat od začátku? Častý případ: ●Velký existující dlouhověký software s problémy ●Nový tým programátorů ho nenávidí a chce ho kompletně přepsat Nový tým dlouho přepisuje ●Buď nikdy nedokončí, nebo v době finalizace (po zpoždění) je to již “Velký existující dlouhověký software s problémy” “Obětovaná architektura” (Sacrificial architecture) ●Tým který navrhoval a implementoval původní architekturu je tým, který rozhoduje že je čas ji “obětovat” ●Je snadné nenávidět kód, který jste nepsali ●Tým který původní kód “psal” má výrazně lepší šanci vytvořit novou užitečnou variantu Keith Parkinson

PB161 Kdy refaktorovat / přepisovat? Navrhujte systém aby obsloužil 10x růst (vzhledem k aktuálním požadavkům) Buďte připraveni kompletně přepsat před 100x nárůstem “At Google, the explicit rule is to design a system for ten times its current needs, with the implication that if the needs exceed an order of magnitude then it's often better to throw away and replace from scratch. It's common for subsystems to be redesigned and thrown away every few years.” PB161 | Šablony, Návrhové principy a vzory,

PB161 Kdy refaktorovat? PB161 | Šablony, Návrhové principy a vzory,