The wiki page is under active construction, expect bugs.

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
statnice:bakalar:b6b36omo [2025/06/12 10:13] – [Behavioral design patterns] prokopstatnice:bakalar:b6b36omo [2025/06/13 07:31] (current) – [Structural design patterns: adapter, proxy, bridge, composite, facade, decorator, flyweight] prokop
Line 395: Line 395:
 </code> </code>
  
-{{statnice:bakalar:omofprototype.png?700}}+{{statnice:bakalar:omoprototype.png?700}}
  
 === Builder === === Builder ===
Line 582: Line 582:
  
 {{statnice:bakalar:sinfacade.png?500}} {{statnice:bakalar:sinfacade.png?500}}
 +
 +=== Composite Design Pattern ===
 +
 + * Účel:
 +  * Umožňuje jednotné zacházení s **jednotlivými objekty** i s **jejich složením (stromová struktura)**.
 +  * Používá se pro reprezentaci **hierarchických struktur** (např. souborový systém, GUI komponenty, organizace).
 +
 + * Struktura:
 +  * **Component** – společné rozhraní pro listy i složené objekty.
 +  * **Leaf** – jednoduchý objekt (např. soubor).
 +  * **Composite** – složený objekt (např. složka obsahující další objekty).
 +
 + * Výhody:
 +  * Rekurzivní zpracování hierarchických struktur.
 +  * Klientský kód se nemusí starat, zda pracuje s listem nebo composite – volá jednotné metody.
 +  * Umožňuje dynamicky přidávat/odebírat prvky.
 +
 +=== Příklad použití: souborový systém ===
 +
 +<code java>
 +  interface FileSystemItem {
 +    void display(String indent);
 +  }
 +
 +  class File implements FileSystemItem {
 +    private String name;
 +
 +    public File(String name) {
 +        this.name = name;
 +    }
 +
 +    public void display(String indent) {
 +        System.out.println(indent + "- File: " + name);
 +    }
 +  }
 +
 +  class Folder implements FileSystemItem {
 +    private String name;
 +    private List<FileSystemItem> children = new ArrayList<>();
 +
 +    public Folder(String name) {
 +        this.name = name;
 +    }
 +
 +    public void add(FileSystemItem item) {
 +        children.add(item);
 +    }
 +
 +    public void display(String indent) {
 +        System.out.println(indent + "+ Folder: " + name);
 +        for (FileSystemItem item : children) {
 +            item.display(indent + "  ");
 +        }
 +    }
 +  }
 +
 +  public class CompositeDemo {
 +    public static void main(String[] args) {
 +        Folder root = new Folder("root");
 +        root.add(new File("readme.txt"));
 +
 +        Folder src = new Folder("src");
 +        src.add(new File("Main.java"));
 +        src.add(new File("Utils.java"));
 +
 +        root.add(src);
 +        root.display("");
 +    }
 +  }
 +</code>
  
 === Decorator === === Decorator ===
Line 888: Line 958:
   * Odděluje algoritmus od struktury dat.   * Odděluje algoritmus od struktury dat.
   * Umožňuje přidat nové operace bez změny datové struktury.   * Umožňuje přidat nové operace bez změny datové struktury.
 +  * Realizace patternu je pomocí tzv. **double dispatch** principu. 
 +    * Elementy datové struktury u kterých chci v budoucnosti přidávat operace, mají metodu accept(Visitor) uvnitř které zavolám na vloženém visitoru metodu visitElement(Element)
 +    * Tím předám řízení visitoru a zároveň mu předám referenci
 <code java> <code java>
    public interface ComputerPart {    public interface ComputerPart {
Line 1016: Line 1089:
   * Umožňuje **měnit chování objektu v závislosti na jeho vnitřním stavu**, aniž bychom museli používat podmínky typu `if` nebo `switch`.   * Umožňuje **měnit chování objektu v závislosti na jeho vnitřním stavu**, aniž bychom museli používat podmínky typu `if` nebo `switch`.
   * Každý stav implementuje vlastní logiku a může přepnout objekt do jiného stavu.   * Každý stav implementuje vlastní logiku a může přepnout objekt do jiného stavu.
 +
  
 <code java> <code java>
-   player.setState(new ReadyState()); +   // Rozhraní pro stav 
-   player.play();  // deleguje na aktuální stav+   public interface State { 
 +       void onPlay(Player player); 
 +       void onLock(Player player); 
 +   } 
 + 
 +   // Kontext – přehrávač 
 +   public class Player { 
 +       private State state; 
 + 
 +       public Player() { 
 +           this.state = new ReadyState();  // výchozí stav 
 +       } 
 + 
 +       public void setState(State state) { 
 +           this.state = state; 
 +       } 
 + 
 +       public void pressPlay() { 
 +           state.onPlay(this); 
 +       } 
 + 
 +       public void pressLock() { 
 +           state.onLock(this); 
 +       } 
 +   } 
 + 
 +   // Konkrétní stav – Ready 
 +   public class ReadyState implements State { 
 +       public void onPlay(Player player) { 
 +           System.out.println("Start playing music."); 
 +           player.setState(new PlayingState()); 
 +       } 
 + 
 +       public void onLock(Player player) { 
 +           System.out.println("Locked from ready state."); 
 +           player.setState(new LockedState()); 
 +       } 
 +   } 
 + 
 +   // Konkrétní stav – Playing 
 +   public class PlayingState implements State { 
 +       public void onPlay(Player player) { 
 +           System.out.println("Paused."); 
 +           player.setState(new ReadyState()); 
 +       } 
 + 
 +       public void onLock(Player player) { 
 +           System.out.println("Locked while playing."); 
 +           player.setState(new LockedState()); 
 +       } 
 +   
 + 
 +   // Konkrétní stav – Locked 
 +   public class LockedState implements State { 
 +       public void onPlay(Player player) { 
 +           System.out.println("Can'play, device is locked."); 
 +       } 
 + 
 +       public void onLock(Player player) { 
 +           System.out.println("Unlocked."); 
 +           player.setState(new ReadyState()); 
 +       } 
 +   } 
 + 
 +   // Ukázka použití 
 +   public class StateDemo { 
 +       public static void main(String[] args) { 
 +           Player player = new Player(); 
 + 
 +           player.pressPlay();  // Start playing music. 
 +           player.pressLock();  // Locked while playing. 
 +           player.pressPlay();  // Can't play, device is locked. 
 +           player.pressLock();  // Unlocked. 
 +           player.pressPlay();  // Start playing music. 
 +       } 
 +   }
 </code> </code>
 {{:statnice:bakalar:omostate.png?700}} {{:statnice:bakalar:omostate.png?700}}
Line 1026: Line 1175:
   * Umožňuje vrátit objekt do předchozího stavu.   * Umožňuje vrátit objekt do předchozího stavu.
   * Využívá se pro `undo`, `redo` funkce.   * Využívá se pro `undo`, `redo` funkce.
 +  * Struktura:
 +    * `Originator` – objekt, jehož stav se ukládá.
 +    * `Memento` – objekt obsahující uložený stav.
 +    * `Caretaker` – spravuje historii mement bez znalosti detailů.
 +
 <code java> <code java>
-   caretaker.saveState(originator.createMemento()); +   // Memento – reprezentuje uložený stav 
-   originator.setState("nový stav"); +   public class Memento { 
-   originator.restore(caretaker.getLastSavedState());+       private final String state; 
 + 
 +       public Memento(String state) { 
 +           this.state = state; 
 +       } 
 + 
 +       public String getState() { 
 +           return state; 
 +       } 
 +   } 
 + 
 +   // Originator – třída s měnitelným stavem 
 +   public class Originator { 
 +       private String state; 
 + 
 +       public void setState(String state) { 
 +           this.state = state; 
 +           System.out.println("Current state: " + state); 
 +       } 
 + 
 +       public Memento saveStateToMemento() { 
 +           return new Memento(state); 
 +       } 
 + 
 +       public void getStateFromMemento(Memento memento) { 
 +           state = memento.getState(); 
 +           System.out.println("State restored to: " + state); 
 +       } 
 +   } 
 + 
 +   // Caretaker – uchovává historii stavů 
 +   public class Caretaker { 
 +       private List<Memento> mementoList = new ArrayList<>(); 
 + 
 +       public void add(Memento state) { 
 +           mementoList.add(state); 
 +       } 
 + 
 +       public Memento get(int index) { 
 +           return mementoList.get(index); 
 +       } 
 +   } 
 + 
 +   // Použití 
 +   public class MementoDemo { 
 +       public static void main(String[] args) { 
 +           Originator originator = new Originator(); 
 +           Caretaker caretaker = new Caretaker(); 
 + 
 +           originator.setState("State #1"); 
 +           originator.setState("State #2"); 
 +           caretaker.add(originator.saveStateToMemento()); 
 + 
 +           originator.setState("State #3"); 
 +           caretaker.add(originator.saveStateToMemento()); 
 + 
 +           originator.setState("State #4"); 
 + 
 +           originator.getStateFromMemento(caretaker.get(0)); // State #2 
 +           originator.getStateFromMemento(caretaker.get(1)); // State #3 
 +       } 
 +   }
 </code> </code>
 {{:statnice:bakalar:omomemento.png?700}} {{:statnice:bakalar:omomemento.png?700}}
  
 === Interpreter === === Interpreter ===
-  * Vyhodnocuje výrazy v definovaném jazyce (např. matematický jazyk)+  * Definuje jazyk (syntaxi + sémantiku) pomocí tříd
-  * Každý prvek jazyka má vlastní třídu.+  * Každý prvek výrazu má svou třídu. 
 +  * Používá se k implementaci jednoduchých jazyků, výrazů, konfigurací, pravidel. 
 +  * Struktura: 
 +    * `Expression` – rozhraní nebo abstraktní třída pro všechny výrazy. 
 +    * `TerminalExpression` – konkrétní výrazy (proměnné, konstanty). 
 +    * `NonTerminalExpression` – operace (např. sčítání, odečítání). 
 +    * `Context` – mapa proměnných (např. {"x" → 10})
 <code java> <code java>
-   Expression exp new Plus( +   // Rozhraní pro výraz 
-       new Variable("w"), +   public interface Expression 
-       new Minus( +       int interpret(Map<String, Integer> context); 
-           new Variable("x"), +   } 
-           new Variable("z"+ 
-       +   // Terminální výraz – proměnná 
-   ); +   public class Variable implements Expression { 
-   Map<String, Integer> context = Map.of("w", 6, "x", 30, "z", 8); +       private String name; 
-   int result = exp.evaluate(context);  // výsledek: 6 + (30 8)+ 
 +       public Variable(String name) { 
 +           this.name name; 
 +       } 
 + 
 +       public int interpret(Map<String, Integer> context) { 
 +           return context.get(name); 
 +       } 
 +   } 
 + 
 +   // Non-terminal – součet 
 +   public class Plus implements Expression { 
 +       private Expression left, right; 
 + 
 +       public Plus(Expression left, Expression right) { 
 +           this.left = left; 
 +           this.right = right; 
 +       
 + 
 +       public int interpret(Map<String, Integer> context) { 
 +           return left.interpret(context) + right.interpret(context); 
 +       } 
 +   } 
 + 
 +   // Non-terminal – rozdíl 
 +   public class Minus implements Expression { 
 +       private Expression left, right; 
 + 
 +       public Minus(Expression left, Expression right) { 
 +           this.left = left; 
 +           this.right = right; 
 +       } 
 + 
 +       public int interpret(Map<String, Integer> context) { 
 +           return left.interpret(context) - right.interpret(context); 
 +       } 
 +   } 
 + 
 +   // Ukázka použití 
 +   public class InterpreterDemo { 
 +       public static void main(String[] args) { 
 +           Expression expr = new Plus( 
 +               new Variable("x"), 
 +               new Minus( 
 +                   new Variable("y"), 
 +                   new Variable("z"
 +               
 +           ); 
 + 
 +           Map<String, Integer> context = Map.of("x", 5, "y", 10, "z", 3); 
 +           int result = expr.interpret(context); // + (10 3= 12 
 + 
 +           System.out.println("Výsledek: " + result); 
 +       } 
 +   }
 </code> </code>
-{{:statnice:bakalar:omointerpreter.png?700}}+{{:statnice:bakalar:omointerpreter.png?500}}
  
 ===== Datové struktury a patterny: lazy loading, object pool, cache map, filter, reduce pattern ===== ===== Datové struktury a patterny: lazy loading, object pool, cache map, filter, reduce pattern =====
 +
 +=== Lazy Loading ===
 +  * Odložené načtení dat z paměti, databáze nebo vzdáleného zdroje.
 +  * Zvyšuje efektivitu, pokud některá data nejsou vždy potřeba.
 +  * Čtyři hlavní implementace:
 +    * **Virtual Proxy** – místo objektu se vrací proxy, která objekt načte při prvním použití.
 +    * **Lazy Initialization** – načítání na základě podmínky `if (obj == null)`.
 +    * **Ghost** – objekt se načítá po částech podle potřeby (např. jen ID, pak detaily).
 +    * **Value Holder** – objekt zabalený v obalu, který řídí načtení hodnoty.
 +
 +<code java>
 +   public class Company {
 +       private ContactList contacts;
 +
 +       public ContactList getContacts() {
 +           if (contacts == null) {
 +               contacts = new ContactListProxy(); // virtual proxy
 +           }
 +           return contacts;
 +       }
 +   }
 +
 +   public class ContactListProxy implements ContactList {
 +       private ContactList realList;
 +
 +       public List<Customer> getCustomers() {
 +           if (realList == null) {
 +               realList = new RealContactList(); // expensive operation
 +           }
 +           return realList.getCustomers();
 +       }
 +   }
 +</code>
 +
 +{{statnice:bakalar:omolazy.png?300}}
 +
 +=== Object Pool ===
 +  * Vzor, který opakovaně používá drahé objekty místo jejich opakovaného vytváření a likvidace.
 +  * Typické použití:
 +    * JDBC připojení (`ConnectionPool`)
 +    * File handle
 +    * HTTP klienti
 +  * Pool může mít parametry: minimální/ maximální počet instancí, TTL, idle cleanup.
 +<code java>
 +   public class ObjectPool<T> {
 +       private BlockingQueue<T> pool;
 +
 +       public ObjectPool(Supplier<T> creator, int maxSize) {
 +           pool = new ArrayBlockingQueue<>(maxSize);
 +           for (int i = 0; i < maxSize; i++) {
 +               pool.offer(creator.get());
 +           }
 +       }
 +
 +       public T borrow() throws InterruptedException {
 +           return pool.take();
 +       }
 +
 +       public void release(T obj) {
 +           pool.offer(obj);
 +       }
 +   }
 +
 +   // Použití:
 +   ObjectPool<Connection> connectionPool = new ObjectPool<>(MyConnection::new, 5);
 +   Connection conn = connectionPool.borrow();
 +   // ...
 +   connectionPool.release(conn);
 + </code>
 +
 + {{statnice:bakalar:omoobjpool.png?300}}{{statnice:bakalar:omoobjpool2.png?300}}
 +
 +=== Cache ===
 +* Vzor, který ukládá data, která se často opakovaně používají.
 +  * Používá se např. pro:
 +    * Konfigurace, katalogy, uživatelská data
 +  * Základní princip:
 +    * `get(key)` → pokud data nejsou nalezena, stáhnout z pomalého zdroje a uložit.
 +  * Eviction policy (např. LRU) zabraňuje přetečení paměti.
 +
 +<code java>
 +   public class SimpleCache<K, V> {
 +       private final int capacity;
 +       private final Map<K, V> cache = new LinkedHashMap<>();
 +
 +       public SimpleCache(int capacity) {
 +           this.capacity = capacity;
 +       }
 +
 +       public synchronized V get(K key, Supplier<V> dataLoader) {
 +           if (!cache.containsKey(key)) {
 +               if (cache.size() >= capacity) {
 +                   Iterator<K> it = cache.keySet().iterator();
 +                   it.next(); it.remove(); // remove oldest
 +               }
 +               cache.put(key, dataLoader.get());
 +           }
 +           return cache.get(key);
 +       }
 +   }
 +
 +   // Použití:
 +   SimpleCache<String, Person> personCache = new SimpleCache<>(100);
 +   Person p = personCache.get("123", () -> loadPersonFromDB("123"));
 +</code>
 + {{statnice:bakalar:omocache.png?400}}
 +
 +=== Map, Filter, Reduce (stream API) ===
 +  * Funkcionální operace na sekvencích dat (např. kolekce) umožňující čistý a efektivní styl programování.
 +  * Vzniká **pipeline** z řetězených operací, které jsou **lazy** vyhodnocovány.
 +
 +  * **Map**: transformace každého prvku.
 +  <code java>
 +     List<String> names = people.stream()
 +         .map(Person::getName)
 +         .collect(Collectors.toList());
 +  </code>
 +
 +  * **Reduce**: agregace prvků do jedné hodnoty.
 +   <code java>
 +     // Příklad z prezentace – nalezení největšího čísla
 +     List<Integer> numbers = Arrays.asList(5, 12, 3, 21, 7);
 +
 +     int max = numbers.stream()
 +         .reduce(Integer.MIN_VALUE, (a, b) -> a > b ? a : b); \\tady passujeme lambda funkci
 +
 +     System.out.println("Maximum: " + max);
 +   </code>
 +
 +  * **Filter**: výběr pouze těch prvků, které splňují predikát.
 +   <code java>
 +     List<Person> fromPraha = people.stream()
 +         .filter(p -> p.getCity().equals("Praha"))
 +         .collect(Collectors.toList());
 +   </code>
 +
 +  * **Kombinování:**
 +  <code java>
 +     List<String> sortedNames = people.stream()
 +         .filter(p -> p.getCity().equals("Praha"))
 +         .map(Person::getName)
 +         .sorted()
 +         .collect(Collectors.toList());
 +  </code>
 +
  
 ===== Specifikace, návrhy specifikací, web API, Apiary, Swagger, GraphQL ===== ===== Specifikace, návrhy specifikací, web API, Apiary, Swagger, GraphQL =====
 +
 +<markdown>
 +### Specifikace
 +
 += Formální popis toho, jak se má komponenta v systému chovat
 +
 + - zahrnuje popis jejích rozhraní, funkcí a očekávaného chování
 + - představuje společný kontrakt pro implementátora komponenty a klienta komponenty
 + - význam specifikace: předchází chybám, srozumitelnost, připravenost na změny
 +
 +
 +**Behaviorální ekvivalence**
 +
 +"Dva kódy jsou behaviorálně ekvivalentní, pokud při stejných vstupech ve stejném kontextu dávají stejné výstupy a vedou ke stejnému stavu systému."
 +
 + - odpovídá na otázku zda-li se dva zdrojové kódy chovají stejně (možnost výměny kódu beze změny chování systému)
 + - není obecně testovatelná
 + - faktory ovlivňující behav. ekvivalenci: Vstupní hodnoty, Kontext běhu, Vedlejší efekty, Chybové stavy
 + - hraje roli i kontrakt mezi klientem a implementací:
 +   - Preconditions = požadavky, které musí klient splnit, než zavolá funkci
 +   - Postconditions = záruky, které funkce poskytne
 +
 +**Změna specifikace** - silná vs. slabá
 +
 +S2 je silnější nebo stejná jako S1 pokud:
 + - Preconditions pro S2 jsou slabší než nebo stejné jako pro S1
 + - Postcondition pro S2 jsou silnější nebo stejné jako pro S1
 +
 +=> můžeme nahradit S1 za S2 bez ovlivnění stávajících klientů
 +
 +**Přesnost popisu specifikace**
 +- Deterministic: jednoznačně určený výstup
 +- Undetermined: není jednozačně určen výstup 
 +
 +Příklad: "vrátí __první__ index i, kde arr[i] = val" vs "vrátí index i, kde arr[i] = val"
 +
 +**Deklarativní vs Operativní specifikace**
 +
 +- Deklarativní: nepopisuje detaily interních kroků implementace, popisuje výstup na základě vstupů
 +- Operativní: popisuje kroky implementace, slouží jako návod pro vývojáře
 +
 +(deklarativní preferovanější)
 +
 +**Testování** - testy musí splňovat podmínky specifikace, testy nesmí být podřízeny implementaci, ale výhradně specifikaci rozhraní
 +
 +### REST (Representational State Transfer)
 +
 += architektonický styl pro návrh webových API (nemusí být nutně vázaný na HTTP protokol)
 +- REST API jsou navrženy na základě resources = objekty/data/služby ke kterým klient přistupuje
 +- každý resource má identifikátor - URI
 +- používá se jednotný interface, aby byl zajištěn decoupling klienta a serveru (v HTTP použito verb v hlavičce - get, put, post, delete, patch)
 +- ! je bezestavový, odpovědi mohou být cacheovány
 +
 +Existují různé úrovně implementace:
 +- Level 0: jedno URI pro všechny operace, operace jsou post volání na toto URI
 +- Level 1: separátní URI pro jednotlivé resources
 +- Level 2: využití HTTP metod pro definici operací na resource
 +- Level 3: využití hypermedia odkazů (odpovědi obsahují URI na další resources např. objednávka -> uri pro položky)
 +
 +**Web API**
 +
 += api na webovém serveru nebo klientu
 +- request response koncept, předávání zpráv ve formátu JSON nebo XML
 +- ve většine řešení postavený na HTTP (využívání response kódů)
 +
 +SOAP (Simple Object Access Protocol)
 +
 +- protokol pro komunikaci mezi 2 zařízeními
 +- pro popis služeb využívá WSDL (web services description language) - formální popis poskytované funkcionality (xml)
 +- zprávy jsou ve formátu XML
 +- zpřístupňuje klientovi funkce a operace (např. může mít funkci CreateEmployee pro vytvoření zaměstnance v systému) -> orientovaná procedurálně
 +- není cachovaný
 +- pomalejší
 +
 +REST API
 +
 +- zpřístupňuje klientovi data -> orientovaná datově
 +- využívá HTTP - metody pro přístup ke zdrojům: get, put, post, delete, patch
 +- podporuje různé formáty - především JSON ale mohou být různé
 +- popis endpointů je méně formální
 +- rychlejší
 +
 +GraphQL
 +
 +- efektivní nástupce REST API
 +- dává možnost specifikace požadovaných dat
 +- když operace vrací objektový graf, tak mohu specifikovat hloubku a podmnožiny atributů jednotlivých entit
 +- zvládá větší zátěž než REST
 +
 +Open API
 +- Open API Initiative - zaměřuje se na vytvoření,zkvalitňování a propagaci formátu pro popis rozhraní, které bude nezávislé na dodavateli
 +- Open API Specification 
 +  - definuje standard pro popis REST API, nezávislé na programovacím jazyku
 +  - může být použita pro generování klientského i serverového kódu pro různé programovací jazyky, generování dokumentace, validace obsahu zpráv, testování
 +
 +Swagger
 +
 +- framework pro definici rozhraní podle specifikace OpenAPI
 +- pokrývá celý životní cyklus REST API:
 +  - návrh - Swagger Editor - nástroj pro psaní OpenAPI specifikace v YAML/JSON
 +  - dokumentace - Swagger UI - vygeneruje interaktivní dokumentaci z OpenAPI popisu
 +  - build - Swagger Codegen - automaticky generuje kód klientů/serverů podle specifikace
 +  - testování - Swagger Inspector - umožňuje testovat API volání přímo z prohlížeče
 +  - deployment - zakomponování do Docker apod.
 +
 +na datové struktury se v rámci zpráv odkazuje pomocí REF - uri
 +
 +APIARY
 +
 +- obdobný nástroj swaggeru
 +
 +</markdown>
Navigation

Playground

QR Code
QR Code statnice:bakalar:b6b36omo (generated for current page)