Modelování obchodních procesů, analytický doménový model, analýza a správa požadavků
Pokrývá diagram aktivit UML pro modelování procesů, UML diagram tříd a stavový diagram pro doménový model, a kompletní analýzu požadavků včetně diagramu případů užití a scénářů.
🔄 Modelování obchodních procesů – účel a přínosy
Než začneme navrhovat software, musíme pochopit, co zákazník aktuálně dělá a jak. Modelování procesů není jen technická formalita – je to způsob, jak odhalit problémy ještě před zahájením vývoje.
- Popsání činnosti zákazníka – pochopení jeho potřeb a problémů z pohledu praxe
- Přesnější specifikace požadavků – víme, co systém musí podporovat
- Lepší podpora procesů v navržené aplikaci
- Zlepšení samotných procesů – bez ohledu na implementaci (re-engineering)
- Identifikace „problémových" míst – kde teče čas nebo vznikají chyby
Manažer vidí procesy idealizovaně. Budoucí uživatelé systému mají různé role a jejich problémy se zásadně liší. Je třeba znát způsob práce všech rolí, ideálně je pozorovat přímo při práci.
Typy modelů procesů:
- AS IS – současný stav procesů, bez ohledu na navrhovaný systém. Slouží k pochopení zákazníka, nalezení problémů a jako podklad pro nové procesy.
- TO BE – stav po realizaci nového systému. Umožňuje srovnání a vyhodnocení přínosů.
Notace pro modelování procesů:
- Eriksson-Penker – rozšíření UML pro podnikové procesy
- BPMN (Business Process Model and Notation) – průmyslový standard, bohatá notace
- Diagram aktivit UML – nejčastěji používaný ve výuce FIT ČVUT
Způsob zachycení: Text je nejdůležitější. Diagram slouží pro snadnější pochopení a ověření. Sledujeme důležitost procesu, četnost provádění a časovou/finanční náročnost.
📊 UML Diagram aktivit
Diagram aktivit zobrazuje tok řízení – jak se systém nebo uživatel pohybuje od jedné akce k druhé, jak se tok větví a jak probíhají paralelní činnosti.
Stavební kameny diagramu aktivit:
Akční uzly – reprezentují činnosti, které se provádějí:
- Akce – základní atomická činnost (zaokrouhlený obdélník)
- Akce spouštějící aktivitu – volá jinou aktivitu jako podproces
- Odeslání události – posílá signál jinému účastníkovi (pentagon s šipkou ven)
- Přijetí události – čeká na příchod signálu (pentagon se šipkou dovnitř)
- Časová událost – akce spuštěná časovačem (přesýpací hodiny)
Řídící uzly – řídí tok:
- Počáteční uzel – plný černý kruh, začátek aktivity
- Koncový uzel aktivity – plný kruh v kroužku, ukončí celou aktivitu
- Konec toku – křížek v kroužku, ukončí pouze jeden tok (ostatní pokračují)
- Rozhodovací uzel (Decision) – diamant, tok se větví na základě podmínky. Podmínky na větvích musí být výlučné – vždy splněna právě jedna!
- Slučovací uzel (Merge) – diamant, sbíhá se více toků do jednoho (bez synchronizace)
- Paralelní Fork – černá tlustá čára, rozdělí jeden tok do více paralelních
- Paralelní Join – černá tlustá čára, počká na dokončení VŠECH paralelních větví
Merge (slučovací uzel) slouží pro sbíhání alternativních toků – propustí první příchozí token. Nezajišťuje synchronizaci. Join (synchronizační uzel) čeká na VŠECHNY paralelní větve. Používá stejnou grafiku (tučná čára), ale sémantika je odlišná. Pokud chceme zachytit cyklus: slučovací uzel nesmíme nahradit přímým zpětným tokem do akce – musíme použít explicitní Merge uzel.
Další prvky diagramu aktivit:
- Zóny zodpovědnosti (swimlanes) – rozdělení diagramu do oblastí odpovídajících rolím nebo systémům. Akce v dané zóně provádí daná role.
- Objektové uzly – zachycují stav objektu přenášeného mezi akcemi (obdélník s názvem třídy, volitelně stav v hranatých závorkách, např.
Výtisk [Vypůjčen]) - Vícenásobné provedení akce (Expansion Region) – akce se provede pro každý prvek kolekce
- Přerušení provádění (Interrupt Region) – region, jehož zpracování lze přerušit výjimečnou událostí; všechny tokeny uvnitř jsou odstraněny
Příklad: uzly A → Decision → B nebo C → D. Možné průchody jsou: A, B, D a A, C, D. U paralelního fork/join: E → Fork → (F a G paralelně) → Join → H. Průchody: E,F,G,H nebo E,G,F,H (pořadí F a G závisí na prostředí, ale H nastane až po obou).
Typická chyba č. 2 – Míchání stavů objektů mezi akce:
Stav objektu (např. „Vypůjčen") nesmí figurovat jako akce v diagramu. Akce způsobují změnu stavu. Správně: přidáme objektový uzel s daným stavem a akci, která stav vyvolá (např. „Zapsat výpůjčku" → Výtisk [Vypůjčen]).
📋 Analýza a správa požadavků
Kategorizace požadavků:
- Projektové požadavky – cena, termíny, školení, způsob dodání
- Produktové požadavky – Funkční – popisují chování systému (co systém dělá). Příklad: „Systém bude evidovat knihy a výtisky."
- Produktové požadavky – Obecné / Nefunkční – určují omezení kladená na systém. Mají zásadní dopad na architekturu. Příklad: „Aplikace zvládne 100 souběžných uživatelů."
Klasifikace nefunkčních požadavků – FURPS:
| Písmeno | Oblast | Příklad požadavku |
|---|---|---|
| F – Functionality | Funkčnost | Systém eviduje výpůjčky |
| U – Usability | Použitelnost | Nový uživatel zvládne práci do 30 minut |
| R – Reliability | Spolehlivost | Dostupnost 99,9 % (max. 8,7 h výpadku/rok) |
| P – Performance | Výkon | Odezva do 2 sekund pro 100 uživatelů |
| S – Supportability | Podporovatelnost / rozšiřitelnost | Systém bude rozšiřitelný o nové knihovny |
Evidované informace o požadavku:
- Název a zkratka (usnadňuje odkazování, např. F1, N2)
- Popis – nejdůležitější část, musí být jednoznačný
- Typ (kategorie), priorita, složitost
Každý požadavek musí být: Jednoznačný (ne „systém bude výkonný"), Splnitelný a Ověřitelný (splnění musí jít prokázat v rámci akceptačního testování). Příklady špatných požadavků: „Systém bude přívětivý", „Systém bude spolehlivý".
Způsoby zachycení požadavků:
- Strukturovaný text – přirozený jazyk s pevnou šablonou
- Uživatelské příběhy (User Stories) – psány z pohledu uživatele, typické pro agilní vývoj. Nesnaží se popsat kompletní chování celého systému.
- Use Case model – detailní zachycení funkčních požadavků
👤 Model případů užití (Use Case Model)
Využití: vyjasnění požadavků se zákazníkem, základ pro uživatelskou příručku, podklady pro akceptační testy, zpřesnění odhadů pracnosti, zadání pro programátora.
Složení modelu případů užití:
- Seznam aktérů – každý aktér je popsán (kdo je, jakou roli zastává)
- Diagramy případů užití – grafický přehled
- Seznam případů užití – každý případ užití obsahuje název, zkratku, popis (cíl), scénáře (hlavní, alternativní, výjimky) a podmínky provedení
Aktér:
- Role, která má zájem využívat funkčnosti systému pro dosažení cíle
- Vždy se jedná o externí entitu – mimo modelovaný systém
- Jedna konkrétní osoba může zastávat více rolí současně
- Speciální aktér: Čas – automaticky spouštěné úlohy na základě časové události
- Mezi aktéry lze použít generalizaci/dědičnost – potomek může spouštět i všechny případy užití svého rodiče
UML Diagram případů užití:
- Patří do skupiny diagramů chování (UML Behavioral – Use Case)
- Aktér – panáček (stickman) nebo obdélník se stereotypem
- Případ užití – elipsa s názvem uvnitř hranice systému
- Hranice systému – obdélník ohraničující všechny případy užití
- Asociace – čára mezi aktérem a případem užití
- «include» – povinná součást, vždy se provede; vyčleňuje sdílené části scénářů (přerušovaná šipka od UC k inkludovanému UC)
- «extend» – volitelné rozšíření; nepovinná část, provede se jen za určitých podmínek (přerušovaná šipka od rozšíření k základnímu UC)
- Diagram případu užití NEZNÁZORŇUJE tok událostí – k tomu slouží textové scénáře nebo diagram aktivit
- Diagram NEZNÁZORŇUJE datová úložiště (databáze, soubory)
- Případ užití nevyužívaný žádným aktérem nemá smysl (nebo chybí aktér)
- Zachycení činností prováděných MIMO systém – ty patří do modelu obchodních procesů
Scénáře případů užití:
- Hlavní scénář – standardní průchod bez chyb a výjimek. Číslovaný seznam kroků (střídají se aktér a systém). Příklad: 1. Aktér klikne, 2. Systém zobrazí formulář, 3. Aktér vyplní…
- Alternativní scénář – odlišný průchod existující část scénáře (např. jiný způsob vložení fotografie)
- Výjimky – chybové stavy (např. nevalidní ISBN)
- Podmínky provedení – vstupní (pre-condition) a výstupní (post-condition)
Granularita případů užití:
- Jeden scénář cca 10 kroků
- Umožňuje uživateli splnit konkrétní cíl, jehož provedení trvá řádově hodiny
- Případ užití musí mít přínos pro uživatele, který ho provádí
- Popisujte „co" musí systém dělat, vyhněte se popisu „jak" to bude dělat
- Detailní scénáře pište pouze u „zajímavých" UC
- Nepřepisujte neustále stejné jednoduché kroky do každého UC (použijte «include»)
- Pokud je scénář složitý (více alternativních toků), doplňte diagram aktivit
- Pochopení UC velmi usnadňuje grafický návrh obrazovky (wireframe)
🗂️ Analytický doménový model – UML diagram tříd
Cíle: popsat data a jejich meaning (slovníček pojmů), popsat vazby mezi entitami, identifikovat stavy entit, poskytnout základ pro návrh (databázový model, návrhový model tříd).
UML Diagram tříd – základní prvky:
- Třída – obdélník rozdělený na tři části: název, atributy (název:typ), metody
- Viditelnost:
-private,#protected,+public - Atribut vs. asociace – v analytickém modelu preferujeme asociaci (vazbu), protože je názornější a vyjadřuje relaci mezi entitami. Sémanticky jsou ekvivalentní.
Typy vztahů:
| Vztah | Symbol | Popis | Příklad |
|---|---|---|---|
| Asociace | Čára | Obecná vazba mezi třídami | Čtenář – Výpůjčka |
| Kompozice | Vyplněný diamant | Silná celek-část: část bez celku neexistuje | Objednávka – Položka objednávky |
| Agregace | Prázdný diamant | Slabší celek-část: část může existovat samostatně | Tým – Hráč (doporučuje se nepoužívat) |
| Generalizace / Dědičnost | Šipka s prázdnou hlavou | Is-a vztah: potomek je speciálním případem rodiče | Knihovník → Uživatel |
Násobnosti (multiplicity):
1– přesně jeden0..1– nula nebo jeden (volitelný)0..*nebo*– nula nebo více1..*– jeden nebo více (alespoň jeden)
Jak hledat třídy:
- Předměty a objekty reálného světa
- Podstatná jména z vytvořených dokumentů (procesní model, UC model, slovníček)
- Kategorie: obchodní transakce (výpůjčka, platba), položky transakcí, produkty a služby (kniha), role a aktéři, fyzické objekty (výtisk), popisy věcí
- Třída obsahuje atributy specifické pro implementaci (getter, setter, id jako primární klíč)
- Doménový model obsahuje softwarové třídy (Controller, DAO, Service) – ne!
- Třída obsahuje cizí klíče místo asociací
- Nevhodné použití dědičnosti – pokud objekt může měnit svůj typ/kategorii, dědičnost nevhodná (místo toho atribut typ)
- Sloučení atributů popisujících instanci a obecný popis do jedné třídy (Výtisk a Kniha musí být dvě třídy)
Asociační třída: Pokud má samotná vazba atributy (např. vazba Výpůjčka mezi Čtenářem a Výtiskem má datum výpůjčky), zavede se asociační třída. Většinou si však vystačíme bez ní – stačí třída Výpůjčka s atributy a asociacemi.
🔀 UML Stavový diagram
Cíle: porozumění životnímu cyklu entit, vyjasnění stavů, ve kterých se může entita nacházet, zachycení událostí vyvolávajících přechod a podmínek, za kterých může změna nastat.
Prvky stavového diagramu:
- Počáteční pseudostav – plný černý kruh (odkud objekt začíná)
- Koncový stav – kruh v kroužku
- Stav – zaoblený obdélník s názvem stavu
- Přechod – šipka mezi stavy s popisem ve formátu:
Událost[Podmínka]/Akce
Syntax přechodu:
- Událost – co přechod spouští (např. vrácenKnihovníkem)
- Podmínka (guard) – v hranatých závorkách, musí být splněna (např. [dne není po termínu])
- Akce – co se provede při přechodu (za lomítkem)
Stavový diagram popisuje stavy jednoho objektu v čase a přechody mezi nimi. Nevznikají zde nové objekty ani se nezachycuje tok dat. Diagram aktivit popisuje tok řízení procesu – sekvenci akcí, větvení, paralelismus. Jsou to různé nástroje pro různé účely.
Příklad – stavový diagram Výtisku:
- Stav Volný → přechod „PůjčenČtenáři" → stav Vypůjčen
- Stav Vypůjčen → přechod „VrácenKnihovníkem" → stav Volný
- Stav Volný → přechod „Vyřazen" → stav Vyřazen
✅ Shrnutí okruhu 1 a kontrolní otázky
Klíčové body k zapamatování:
- Modelování procesů (AS IS / TO BE) předchází specifikaci požadavků – pomáhá pochopit zákazníka
- Diagram aktivit UML má akční uzly, řídící uzly (Decision/Merge, Fork/Join) a objektové uzly (swimlanes); podmínky na větvích musí být výlučné
- Požadavky se dělí na projektové, funkční a nefunkční (FURPS); musí být jednoznačné, splnitelné a ověřitelné
- UC model = aktéři + diagramy UC + scénáře; «include» je povinné, «extend» je volitelné
- Doménový model zachycuje konceptuální entity domény, ne softwarové třídy; stavový diagram zachycuje životní cyklus entity
Kontrolní otázky a odpovědi:
AS IS zachycuje současný stav procesů bez ohledu na nový systém – slouží k pochopení zákazníka. TO BE zachycuje stav procesů po nasazení nového systému – slouží k odhadu přínosů a ověření vhodnosti návrhu.
Funkční požadavky popisují chování systému (co dělá): „Systém eviduje knihy." Nefunkční (obecné) požadavky určují omezení systému: výkon, spolehlivost, použitelnost. Příklad nefunkčního: „Aplikace zvládne 100 souběžných uživatelů." Klasifikace nefunkčních: FURPS.
Aktér je role, která má zájem využívat funkčnosti systému pro dosažení cíle. Vždy je to externí entita – mimo modelovaný systém. Ano, aktérem může být i jiný systém (např. platební brána) nebo čas (pro plánované úlohy).
«include» je povinná součást – inkludovaný UC se vždy provede (fakticky součást scénáře). Šipka míří od základního UC k inkludovanému. «extend» je volitelné rozšíření – provede se pouze za určitých podmínek. Šipka míří od rozšiřujícího UC k základnímu.
Stavový diagram modeluje životní cyklus jednoho objektu – jeho stavy a přechody mezi nimi. Diagram aktivit modeluje tok řízení procesu nebo algoritmu – posloupnost akcí, větvení, paralelismus, několik objektů/rolí najednou.
Doménový model zachycuje koncepty problémové domény zákazníka (věci, se kterými zákazník pracuje). Softwarové třídy (DAO, Controller, Service) jsou implementační rozhodnutí, která patří do návrhového modelu. Smícháním by model ztratil analytickou hodnotu a byl by nepochopitelný pro zákazníka.
Vzory návrhu: třívrstvá architektura, MVC, GoF vzory, GRASP vzory, spolupráce objektů
Pokrývá architektonické vzory pro organizaci systému do vrstev, vzor MVC pro prezentační vrstvu, vybrané GoF vzory (Abstract Factory, State, Adapter), GRASP vzory (Low Coupling, High Cohesion) a UML sekvenční diagram pro zachycení spolupráce objektů.
🎯 GRASP vzory – principy přiřazení zodpovědností
Existuje mnoho způsobů rozdělení úloh mezi třídy a neexistuje jediné správné řešení. GRASP nám dává vodítko, jak rozhodnout.
Informační expert (Information Expert):
Základní princip: Přiřaďte zodpovědnost třídě, která má informace potřebné pro splnění této zodpovědnosti. Proč? Protože tak se minimalizuje nutnost přístupu jiných tříd k datům – data jsou tam, kde se s nimi pracuje.
Nízká provázanost (Low Coupling): Přiřaďte zodpovědnost tak, aby provázanost (počet vazeb mezi třídami) zůstala nízká. Každá třída by si měla co nejvíce vystačit sama. Nízká provázanost zvyšuje znovupoužitelnost a snižuje dopad změn.
Vysoká soudržnost (High Cohesion): Přiřaďte zodpovědnost tak, aby soudržnost třídy zůstala vysoká. Každá třída by měla být zaměřena na jeden úkol. Zvyšuje srozumitelnost systému – zodpovědnost třídy je snadno pochopitelná.
Paradox: „Jedna třída umí všechno" = nízká provázanost, ale nízká soudržnost. „Každá třída jen jedna metoda" = vysoká soudržnost, ale vysoká provázanost. Hledáme rovnováhu!
Ostatní GRASP vzory (pro přehled): Tvůrce (Creator), Řadič (Controller), Polymorfismus, Čistá výroba (Pure Fabrication), Nepřímý odkaz (Indirection), Chráněné variace (Protected Variations)
🏛️ Vícevrstvá (třívrstvá) architektura
Evoluce architektur:
- Monolitická (jednovrstvá) – vše smícháno dohromady (SQL v HTML šabloně). Vhodná pouze pro prototypy, složitá udržovatelnost.
- Dvouvrstvá – oddělena prezentační vrstva od datové (DAO vrstva). Vhodná pro jednoduché CRUD aplikace.
- Třívrstvá – přidána business vrstva. Vhodná pro enterprise aplikace.
- Vícevrstvá – třívrstvá s dalším dělením na podsystémy.
| Vrstva | Zodpovědnost | Příklady |
|---|---|---|
| Prezentační | Zobrazení dat uživateli, zpracování vstupu, navigace, formátování výstupů | HTML stránky, šablony, REST API, GUI |
| Business (doménová) | Business logika, procesy a validace. Nezávislá na prezentační i datové vrstvě. | SpravceCtenaru, VypujckaService |
| Datová (technická) | Persistence dat, přístup k databázi nebo externím službám | CtenarDAO, HibernateRepository |
Striktní vs. Relaxovaná třívrstvá architektura:
- Striktní – závislost vždy směrem dolů a pouze o jednu úroveň (prezentační → business → datová). Čistější, ale méně flexibilní.
- Relaxovaná – závislost vždy dolů, ale přes libovolný počet úrovní. V praxi nejvíce používaná.
- Oddělení business logiky od prezentace – logiku lze testovat bez GUI
- Nezávislost business logiky na způsobu uložení dat – lze vyměnit DB technologii
- Více různých prezentačních vrstev (webová, mobilní API, desktop)
- Znovupoužitelnost: čím nižší vrstva, tím lze ji použít na více projektech (logování, persistence)
- Jednoduché testování – mockování vrstev je přímočaré
🖥️ Model View Controller (MVC)
Komponenty MVC:
- Model – zapouzdřuje data a business logiku. Notifikuje View o změnách (vzor Observer). Dvě varianty:
- Aktivní model – sám upozorní View na změny (Observer pattern)
- Pasivní model – pouze reaguje na dotazy, Controller zajistí obnovení View
- View – zobrazuje data z Modelu uživateli. Nezahrnuje business logiku. Může být více View pro jeden Model.
- Controller – zpracovává uživatelský vstup (klik, formulář), volá metody Modelu a určuje, která View se zobrazí.
Vztah MVC a třívrstvé architektury:
MVC je vzor pro prezentační vrstvu třívrstvé architektury. Model v MVC volá Business vrstvu, Controller orchestruje. View a Controller jsou součástí prezentační vrstvy.
MVP (Model-View-Presenter): Varianta MVC pro GUI based na komponentách (Swing, WinForms). View odchytí událost, ale deleguje zpracování na Presenter. View implementuje rozhraní, které Presenter volá.
Příklady frameworků MVC/MVP:
- Spring MVC, Grails – Java
- JSF 2, MyFaces – Java EE (spíše MVP)
- Angular, React – JavaScript (MVVM varianta)
- ASP.NET MVC – .NET
🏭 GoF návrhové vzory
Abstraktní továrna (Abstract Factory) – Creational:
Řeší problém vytváření rodiny/varianty objektů. Klient pracuje pouze s rozhraním továrny a nemusí znát konkrétní třídy produktů.
- AbstractFactory – rozhraní/abstraktní třída definující metody pro vytváření všech produktů
- ConcreteFactory – konkrétní implementace pro danou variantu (např. TestFactoryDAO, HibernateFactoryDAO)
- AbstractProduct – rozhraní produktu (ICtenarDAO, IVypujckaDAO)
- ConcreteProduct – konkrétní implementace produktu
Proč to tak je? Při vývoji chceme testovat bez databáze (TestFactoryDAO vrátí mock objekty). V produkci použijeme HibernateFactoryDAO. Kód klienta se nezmění.
SpravceCtenaru dostane factory (buď TestFactory nebo HibernateFactory) a přes ni vytvoří ICtenarDAO a IVypujckaDAO. Ať už je factory jakákoliv, SpravceCtenaru funguje stejně.
Vzor Stav (State) – Behavioral:
Odděluje chování třídy závislé na stavu do samostatné třídy. Odstraňuje složitá větvení (switch/case, if/else) závislá na stavu objektu.
- Context – třída, jejíž chování se mění v závislosti na stavu (např. Výtisk). Udržuje referenci na aktuální stav.
- State – abstraktní třída/rozhraní pro všechny stavy
- ConcreteState – konkrétní stavy (StavVolny, StavVypujcen) – každý implementuje jiné chování metod
Proč to tak je? Bez vzoru State by metoda zpracuj() obsahovala: if (stav == VOLNY) {...} else if (stav == VYPUJCEN) {...}. S přidáním nového stavu bychom museli modifikovat tuto metodu. Se vzorem State přidáme pouze novou třídu stavu.
Adaptér (Adapter) – Structural:
Konvertuje rozhraní jedné třídy na rozhraní jiné. Umožňuje propojit třídy s nekompatibilními rozhraními bez jejich modifikace.
- Target – rozhraní, které klient očekává
- Adaptee – existující třída s jiným rozhraním
- Adapter – implementuje Target rozhraní a deleguje volání na Adaptee
Příklad z praxe: Naše aplikace očekává rozhraní IPlatebniSluzba. Integrujeme nový platební gateway, jehož API je zcela jiné. Napíšeme Adapter, který překládá volání z IPlatebniSluzba na API gateway.
Stavitel (Builder) – Creational:
- Director – řídí strukturu (pořadí stavění) výsledného produktu
- Builder – umí postavit jednotlivé části produktu v konkrétní „technologii"
- Příklad z přednášky: SQLBuilder – Director řídí, co a v jakém pořadí se přidá do SQL scriptu; konkrétní Builder (OracleBuilder, PostgreSQLBuilder) to realizuje pro danou DB.
Pozorovatel (Observer) – Behavioral:
- Pozorující objekty se zaregistrují u pozorovaného objektu
- Musí implementovat požadované rozhraní (IObserver)
- Při změně upozorní pozorovaný objekt všechny pozorující touto metodou
- Využití: aktivní Model v MVC upozorňuje View na změny
📞 Spolupráce objektů – UML Sekvenční diagram
Prvky sekvenčního diagramu:
- Lifeline (životní čára) – svislá přerušovaná čára znázorňující životnost objektu. Nahoře je obdélník s názvem objektu ve formátu
nazev:Tridanebo anonymně:Trida. - Aktivační obdélník – úzký obdélník na životní čáře znázorňující dobu, kdy je objekt aktivní (vykonává kód)
- Synchronní zpráva – plná šipka → , volající čeká na odpověď
- Asynchronní zpráva – otevřená šipka → , volající nečeká
- Návratová hodnota – přerušovaná šipka zpět, s názvem proměnné/hodnoty
- Statická metoda – volání na třídě, ne na objektu (podtžený název třídy)
- Vytvoření objektu – šipka míří na obdélník nového objektu
- Zrušení objektu – X na konci životní čáry
- Self message – šipka zpět na vlastní lifeline (volání vlastní metody)
- Found message – zpráva s neznámým odesílatelem (začíná plným kruhem)
Kombinované fragmenty (framing):
- alt – alternativa (if-else); každá větev má guard podmínku v hranatých závorkách
- opt – volitelné (if bez else)
- loop – cyklus; guard podmínka nebo
loop(min, max) - par – paralelní provedení
- ref – odkaz na jiný diagram
Iterace přes kolekci: Označuje se smyčkou, uvnitř je notace [foreach prvek : kolekce]
✅ Shrnutí okruhu 2 a kontrolní otázky
Klíčové body:
- GRASP: Informační expert, Nízká provázanost, Vysoká soudržnost – základ pro správné přiřazení zodpovědností
- Třívrstvá architektura: Prezentační → Business → Datová; závislosti pouze dolů; výhody: testovatelnost, výměnitelnost vrstev
- MVC: Model (data+logika), View (zobrazení), Controller (vstup) – vzor pro prezentační vrstvu
- Abstract Factory: tvoří rodinu objektů přes rozhraní; State: chování podle stavu; Adapter: překlad rozhraní
- Sekvenční diagram zachycuje spolupráci objektů v čase při realizaci scénáře UC
Abychom oddělili zodpovědnosti, dosáhli nízké provázanosti a vysoké soudržnosti. Business logika je nezávislá na způsobu zobrazení i způsobu uložení dat. Systém lze testovat, rozšiřovat a měnit jednotlivé vrstvy bez dopadů na ostatní.
Prosté rozhraní (ICtenarDAO) řeší záměnitelnost jednoho objektu. Abstract Factory řeší záměnitelnost celé rodiny objektů najednou – zaručuje, že všechny spolu vytvořené objekty jsou kompatibilní (TestFactory vrátí všechny mock objekty, HibernateFactory vrátí všechny persistentní). Nelze omylem smíchat test a produkční implementace.
Bez State: každá metoda obsahuje switch/if-else podle aktuálního stavu → při přidání stavu musíme modifikovat všechny metody. Se State: každý stav je třída s implementací metod. Přidání stavu = nová třída, stávající kód se nemění. Splňuje Open/Closed Principle.
Nízká provázanost znamená, že třída má minimum závislostí na ostatních třídách. Při změně jedné třídy nejsou dotčeny ostatní. Zvyšuje to znovupoužitelnost (třída funguje i v jiném kontextu) a snižuje dopad změn v systému.
Popisuje realizaci scénáře případu užití pomocí spolupracujících objektů. Zachycuje, jaké zprávy (metody) si objekty navzájem posílají a v jakém pořadí. Pomáhá přiřadit zodpovědnosti třídám a dokumentovat architektonická rozhodnutí.
Konstrukce, objektové paradigma, základní pravidla návrhu (SRP, LSP, DRY), refactoring
Pokrývá objektové programování (třída, objekt, zapouzdření, dědičnost, polymorfismus), principy správného návrhu kódu a techniky refactoringu pro udržování kvality zdrojového kódu.
🧩 Objektové paradigma
Základní pojmy:
Třída je šablona (blueprint), podle které se vytvářejí objekty. Definuje:
- Metadata atributů (název, typ, viditelnost)
- Signatury metod (název, parametry, návratový typ)
- Implementace metod
- Konstruktory pro inicializaci atributů při vytvoření objektu
Objekt (instance třídy):
- Hodnoty atributů patří konkrétnímu objektu – nejsou sdílené mezi instancemi
- Implementace metod je sdílená pro všechny objekty dané třídy
Čtyři pilíře OOP:
1. Zapouzdření (Encapsulation):
- Objekt je „black box" – drží svůj stav uvnitř sebe sama
- Implementační detaily jsou schovány za množinou veřejných metod
- Přímý přístup k atributům je zakázán (private), k dispozici jsou gettery/settery
- Proč? Umožňuje měnit vnitřní implementaci bez ovlivnění vnějšího kódu. Chrání před nekonzistentním stavem.
2. Dědičnost (Inheritance):
- Podtřída (potomek) přebírá atributy a metody nadtřídy (rodiče)
- Metody podtřídy mohou překrýt (override) metody nadtřídy
- Ve většině jazyků pouze jednoduchá dědičnost (Java, C#)
- Výhoda: kód rodiče se znovu použije, potomci přidávají specifika
Abstraktní třída:
- Atributy a metody (i abstraktní – bez implementace) jsou povoleny
- Konstruktory jsou povoleny, ale nelze je použít pro vytváření instancí
- Podtřída musí implementovat všechny abstraktní metody, nebo musí být také abstraktní
3. Polymorfismus (Polymorphism):
- Při volání metody je implementace určena typem objektu (dynamická vazba), ne typem referenční proměnné
- Příklad: proměnná typu
Zivocich zv = new Pes(). Volánízv.zvuk()zavolá metodu třídy Pes, ne Zivocich. - Proč? Umožňuje psát generický kód pracující s rozhraním – konkrétní chování dodají potomci.
4. Abstrakce (Abstraction):
- Skrytí implementačních detailů za rozhraní nebo abstraktní třídu
- Klient pracuje s abstraktem, nevidí konkrétní implementaci
UML objektový diagram: Patří do diagramů struktur. Zobrazuje konkrétní instance (objekty) a jejich aktuální stav (hodnoty atributů) v daném čase. Usnadňuje pochopení diagramu tříd – jde o „snímek" systému.
📐 Základní principy návrhu: SRP, LSP, DRY
SRP – Single Responsibility Principle (Princip jediné zodpovědnosti):
Každá třída (ale i metoda) by měla mít právě jednu přesně definovanou zodpovědnost. Přeloženo: třída by se měla měnit pouze z jednoho důvodu.
- Proč? Třída s jednou zodpovědností je snadněji pochopitelná, testovatelná a méně pravděpodobně se rozbije při změnách jiných částí systému.
- Signál porušení SRP: prázdný řádek v těle metody nebo komentář v těle metody – indikuje, že metoda dělá více věcí (kandidát na extrahování)
- Příklad porušení: třída
Uzivatelobsahuje metody pro ověření, ukládání do DB i odesílání emailu. - Příklad splnění: samostatné třídy
AutentizacniSluzba,UzivatelDAO,EmailService
LSP – Liskov Substitution Principle (Liskovův substituční princip):
Pokud instanci nadtřídy nahradíme instancí podtřídy, pak kód očekávající instanci nadtřídy by měl fungovat správně i s instancí podtřídy.
- Proč? Dědičnost by měla být skutečně IS-A vztah, ne jen sdílení implementace. Porušení LSP způsobuje nečekané chyby při polymorfismu.
- Klasický příklad porušení:
Ctverec extends Obdelnik. Čtverec má vždy stejnou šířku a výšku. Pokud zavoláme na obdélníksetSirka(2)asetVyska(3), očekáváme obsah 6. Ale pokud je to čtverec,setVyska(3)nastaví šířku i výšku na 3, obsah bude 9, ne 6. LSP je porušen. - Řešení: nesnažit se modelovat matematické vztahy přes dědičnost, pokud mají různé kontrakty
Dědičnost je velmi silná vazba. Většina jazyků umožňuje pouze jednoduchou dědičnost. Vícenásobná dědičnost většinou porušuje vysokou soudržnost a způsobuje problémy (diamond problem). Příklady nevhodné dědičnosti: Fronta extends ZřetězenýSeznam, Bod extends Čtverec. Lepší řešení: kompozice (Fronta obsahuje ZřetězenýSeznam).
DRY – Don't Repeat Yourself (Neopakuj se):
Každý kus znalosti (logika, data, konfigurace) by měl mít v systému jednu jednoznačnou autoritativní reprezentaci.
- Proč? Duplikace kódu je zdroj chyb – při opravě chyby musíme najít a opravit všechny kopie. Při přidání funkce musíme přidat na více místech. Snadno se opomene jedno místo.
- DRY pro kód – zapouzdřit opakující se logiku do metody nebo třídy
- DRY pro data – správný návrh způsobu ukládání dat (normalizace); používání pojmenovaných konstant místo „magic numbers"
Pozor: Ne vždy je copy-paste porušením DRY! Pokud dvě části kódu vypadají podobně, ale jsou logicky nezávislé a mohou se vyvíjet odděleně, spojování je předčasná abstrakce. Musíme rozlišit náhodnou shodu od skutečné duplikace logiky.
Don't talk to strangers (Zákon Démétry):
V metodě objektu je možné volat pouze:
- Jiné metody tohoto objektu (
this.metoda()) - Metody objektů, které vlastní (atributy)
- Metody objektů, které vytváří
- Metody objektů, které dostala jako parametr
Porušení: order.getCustomer().getAddress().getCity() – volám metody „cizích" objektů přes řetězec. To zvyšuje provázanost.
Programování proti rozhraní:
- Rozhraní (interface) je kontrakt: definuje, co objekt umí, ne jak to dělá
- Rozhraní všude tam, kde jsou očekávány změny nebo rozšíření
- Zveřejněné rozhraní by mělo být „neměnné" – klienti závisí na kontraktu, ne na implementaci
- Signatura = název metody + parametry + návratový typ + výjimky
- Kontrakt = povolené hodnoty parametrů, garantovaná chování
🛡️ Další principy správné konstrukce
Ošetření chyb:
- Chránit program před nevalidními vstupy (importy, uživatelské vstupy, API)
- Způsoby zpracování chyby: vrácení neutrální hodnoty, zalogování varování, vrácení chybového kódu, vyvolání výjimky, ukončení programu
- Pozor: Vrácení neutrální hodnoty (null, 0) může „zamaskovat chybu" – problém se projeví až jinde a obtížně se debuguje
Logování:
- Úrovně: DEBUG, INFO, WARN, ERROR, FATAL
- Logger – třída pro zápis do logu; Appender/Handler – kam se logy zapisují (soubor, konzole, email, databáze)
- Formátování logů: datum, čas, zpráva, úroveň, třída
- Existující řešení: Java Logging (JUL), LOG4J, SLF4J (fasáda), NLog (.NET)
Štábní kultura (konvence psaní kódu):
- Pojmenování tříd, metod a parametrů musí být srozumitelné a samopopisné
- PascalCase pro třídy, camelCase pro metody/proměnné, SNAKE_CASE pro konstanty
- Špatný kód:
float z = 50+y(x.x());. Dobrý kód:float pokuta = pokutaZaZpozdeni(delkaZpozdeni); float celkem = SPRAVNI_POPLATEK + pokuta; - Konfigurace do externích souborů (ne hardcoded konstanty v kódu) – umožňuje přizpůsobení prostředím bez rekompilace
- Texty GUI do externích souborů – umožňuje lokalizaci
Délka metody: Čím delší metoda, tím vyšší pravděpodobnost chyby. Doporučení: jedna obrazovka (100-200 řádků max). Prázdný řádek v metodě = signál pro extrahování.
Nepodřizovat návrh optimalizaci: Není vhodné optimalizovat předčasně. Je důležitější připravit kód na budoucí změny. Optimalizovat teprve po profileru.
♻️ Refactoring
Proč refactoring? Kód se degraduje časem (technický dluh). Refactoring ho udržuje srozumitelným, testovatelným a rozšiřitelným. Investice do refactoringu snižuje budoucí náklady na údržbu.
Příznaky, kdy je vhodné začít s refactoringem (Code Smells):
- Duplicity – stejný nebo velmi podobný kód na více místech (porušení DRY)
- Dlouhé metody – metoda dělá příliš mnoho, těžko se čte a testuje
- Velké třídy – třída má příliš mnoho zodpovědností (nízká soudržnost, porušení SRP)
- Příliš mnoho parametrů – metoda s více než 3-4 parametry je příznakem špatné abstrakce
- Komentáře – vysvětlující komentář v kódu je příznakem, že kód není dostatečně samopopisný
- Složité struktury podmínek – hluboce zanořené if/else nebo long switch
- Nedodržené jmenné konvence
Testy jsou „záchranná síť" při refactoringu. Bez nich nemůžeme prokázat, že jsme nezměnili chování. Každý krok refactoringu musí být ověřen spuštěním testů.
Vybrané techniky refactoringu:
| Technika | Popis | Kdy použít |
|---|---|---|
| Přejmenování metody | Přejmenovat metodu tak, aby název jasně vyjadřoval záměr | Název metody není srozumitelný nebo je zavádějící |
| Extrahování metody | Vyčlenit část kódu do nové metody se smysluplným názvem | Dlouhá metoda, duplikace, komentář v kódu |
| Zapouzdření atributu | Nahradit přímý přístup k atributu getter/setter metodami | Public atribut nebo potřeba validace při přístupu |
| Nahrazení dědičnosti delegováním | Místo dědičnosti použít kompozici + delegování | Porušení LSP, nevhodná dědičnost |
| Nahrazení chybového kódu výjimkou | Místo -1 nebo null vrátit výjimku při chybě | Chybový kód se ignoruje nebo maskuje problém |
| Skrytí metody | Změnit viditelnost metody z public na private/protected | Metoda je pouze interní detail implementace |
| Zavedení Null objektu | Místo vracení null vrátit speciální objekt s neutrálním chováním | Kód je plný kontrol if (x != null) |
| Zavedení objektu jako parametru | Nahradit skupinu parametrů jedním objektem | Metoda má příliš mnoho parametrů, které spolu logicky souvisí |
✅ Shrnutí okruhu 3 a kontrolní otázky
Klíčové body:
- OOP: třída je šablona, objekt je instance; 4 pilíře: zapouzdření, dědičnost, polymorfismus, abstrakce
- SRP: každá třída/metoda má jednu zodpovědnost a mění se z jednoho důvodu
- LSP: podtřída musí být plnohodnotnou náhradou nadtřídy; Ctverec extends Obdelnik LSP porušuje
- DRY: každá znalost jedenkrát; duplicita je hlavní zdroj chyb při údržbě
- Refactoring: změna struktury bez změny chování; nutné testy; code smells: duplicity, dlouhé metody, velké třídy
Polymorfismus umožňuje, aby volání metody na referenci nadtřídy vedlo k vykonání implementace konkrétního potomka za běhu programu (dynamic dispatch). Díky tomu lze psát generický kód pracující s abstrakcí – konkrétní chování dodá potomek, aniž bychom museli měnit existující kód. Podstata Open/Closed Principle.
Třída Report, která načítá data z DB, formátuje je a tiskne, má tři zodpovědnosti. Pokud se změní formát tisku, musíme modifikovat třídu Report, i když logika načítání dat zůstala stejná. SRP: rozdělit na ReportRepository (načítání), ReportFormatter (formátování) a ReportPrinter (tisk).
Obdélník má kontrakt: po setSirka(2) a setVyska(3) je obsah 6. Čtverec musí mít vždy sirka == vyska, takže setVyska(3) změní i šírku na 3 → obsah 9, ne 6. Kód pracující s Obdelnikem selže, pokud dostane Ctverec. LSP je porušen. Řešení: Ctverec a Obdelnik jako souřadné třídy bez dědičnosti.
Code smells jsou indikátory problémů v kódu: duplicity, dlouhé metody, velké třídy (nízká soudržnost), příliš mnoho parametrů, komentáře vysvětlující záměr, složité podmínky. Postup refactoringu: 1) ujistit se, že máme testy; 2) provést malý, cílený krok (extrahovat metodu, přejmenovat, atd.); 3) spustit testy; 4) opakovat.
Nesmíme použít dědičnost jen proto, že třídy sdílejí atributy nebo implementaci. Dědičnost je vhodná pouze pro skutečný IS-A vztah, kde podtřída splňuje LSP. Nevhodné: objekt může měnit svůj typ (místo toho stavový vzor nebo atribut); třída nemá žádné nové atributy/metody nad rodičem (stačí atribut typ); vícenásobná dědičnost se složitými vztahy (preferovat kompozici).