The wiki page is under active construction, expect bugs.

This is an old revision of the document!


Principy objektového stylu. Typické příklady objektových řešení. Návrhové vzory.

Klíčové koncepty modelování systémů: programovací paradigmata, dekompozice, hierarchie, abstrakce používané v softwarovém vývoji (jmenné, datové, funkcionální, objektové, SOLID, DRY).

Programovací paradigmata

  • Způsoby, jak strukturovat a přemýšlet o programu. Mezi hlavní patří:
    • Procedurální (imperativní) – program jako posloupnost kroků a manipulace se stavem.
    • Funkcionální – program je složen z funkcí bez side efektů, práce s immutable daty.
    • Objektové – svět tvoří objekty, které spolu komunikují zprávami.
    • Logické – program se skládá z faktů a pravidel, odpovědi se získávají odvozením (např. Prolog).

Deklarativní vs imperativní přístup

  • Deklarativní: popisuje *co* chceme dosáhnout (např. SQL, HTML).
  • Imperativní: popisuje *jak* máme něco provést (např. Java, C).

Dekompozice

  • Rozdělení systému na menší části (moduly, komponenty, objekty) pro snadnější pochopení a správu.
  • Podporována principy:
    • Cohesion – funkce uvnitř modulu by měly logicky souviset.
    • Coupling – minimalizujeme závislosti mezi moduly.
    • Reusability – kód se dá snadno znovu použít.
    • DRY (Don't Repeat Yourself) – stejná funkcionalita není duplikovaná.

Hierarchie

  • Uspořádání tříd a objektů do struktur dle vztahů „is-a“, „has-a“ apod.
  • V objektově orientovaném designu běžně používáme dědičnost, kompozici a polymorfismus.
  • Is-a – dědičnost, třída potomek je podtypem předka.
  • Has-a – kompozice/agregace, objekt obsahuje jiný objekt.

Abstrakce v softwarovém vývoji

  • Jmenná abstrakce – názvy proměnných, funkcí, tříd, modulů.
  • Datová abstrakce – práce s datovými typy bez znalosti jejich vnitřní struktury (např. ADT, interface).
  • Procedurální abstrakce – přístup k funkcím/subrutinám přes rozhraní, bez znalosti implementace.
  • Funkcionální abstrakce – funkce jako hodnoty, vyšší funkce, čisté výpočty.
  • Objektová abstrakce – objekty skrývají stav, interagují přes metody (rozhraní).

Principy návrhu

* SOLID principy:

  • S – Single Responsibility – každá třída má mít jeden důvod ke změně.
  • O – Open/Closed – třídy mají být otevřené rozšíření, uzavřené modifikaci.
  • L – Liskov Substitution – podtypy musí být zaměnitelné za své nadtypy.
  • I – Interface Segregation – lépe více specifických rozhraní než jedno obecné.
  • D – Dependency Inversion – závislost má být na abstrakcích, ne konkrétních třídách.

* DRY (Don't Repeat Yourself)

  • Každá znalost systému by měla být reprezentována pouze jednou.
  • Zamezuje duplicitě, usnadňuje údržbu a testování.

Shrnutí

  • Modelování systémů vyžaduje správnou kombinaci abstrakce, dekompozice a hierarchie.
  • Různá programovací paradigmata určují, jak systém strukturujeme.
  • Použití principů jako SOLID a DRY pomáhá vytvářet kvalitní, udržitelný software.

Objektově orientovaný přístup: objekty, třídy a hierarchie tříd, zapouzdření, interface a abstraktní třídy, dědičnost, class diagramy a příklady systémů modelovaných pomocí OOP, encapsulation, rozdíl mezi asociací, agregací a kompozicí, dědičnost versus kompozice, polymorfismus, overloading versus overriding.

Objekty a třídy

  • Objekt je entita obsahující stav (atributy) a chování (metody).
  • Třída je předpis pro vytvoření objektů – definuje atributy a metody.
  • Z jedné třídy lze vytvořit více instancí (objektů), které sdílí metody, ale mají vlastní stav.

Zapouzdření (encapsulation)

  • Schování vnitřní reprezentace objektu před okolím.
  • K datům se přistupuje výhradně přes veřejné metody (get/set).
  • Zvyšuje bezpečnost, modularitu a odolnost vůči změnám.

Interface a abstraktní třídy

  • Interface – definuje smlouvu: jaké metody musí třída implementovat.
    1. Všechny metody jsou implicitně public a nemají implementaci (kromě default/private metod v novějších verzích).
  • Abstraktní třída – částečná implementace, může obsahovat i neabstraktní metody.
    1. Nelze ji instanciovat, ale lze z ní dědit a rozšiřovat ji.
    2. Abstraktní třída může mít atributy, konstruktor a přístupová práva (public/protected/private).

Interface použijeme, jestliže:

  • 1. Vytvářím vnější rozhraní k objektům – tedy veřejné API ke své komponentě.
  • 2. Chci, aby i objekty z jiné class hierarchie implementovaly stejné rozhraní.
  • 3. Předepisuju pouze metody a nikoliv jejich implementaci – cílem není sdílená logika.
  • 4. Chci předepsat třídě, aby implementovala metody z více rozhraní současně.

Abstraktní třídu použijeme, jestliže:

  • 1. Chci sdílet kód mezi více třídami a neexistuje „neabstraktní“ předek těchto tříd.
  • 2. Třídy jsou mezi sebou úzce spjaté – sdílí mnoho proměnných a metod.
  • 3. Potřebujeme předepsat i metody, které neslouží k vnější komunikaci s objektem, tedy `private` a `protected`.
  • 4. Chci předefinovat proměnné, které nejsou `static` a `final`.

Dědičnost

  • Třída může zdědit vlastnosti a chování jiné třídy (superclass → subclass).
  • Podporuje opětovné použití kódu a hierarchii typů.
  • `extends` – pro třídy, `implements` – pro rozhraní.

Dědičnost vs. Kompozice

  • Dědičnost – silné propojení, změna předka ovlivní potomky.
  • Kompozice – objekt má jiné objekty jako součást svého stavu.
  • Kompozice je flexibilnější, vhodná pro dynamické chování, ale někdy vede k duplicitám.

Class diagramy a příklady

  • UML Class Diagram ukazuje třídy, atributy, metody a vztahy (dědičnost, asociace…).
  • Příklady systémů vhodných pro OOP:
    1. Systém knihovny (knihy, katalogy, účty, členové).
    2. Správa objednávek (objednávka, zákazník, produkt, sklad).

Asociace, agregace, kompozice

  • Asociace – slabý vztah, objekty žijí nezávisle (např. student – kurz).
  • Agregace – silnější, ale objekty stále žijí nezávisle (např. tým – hráči).
  • Kompozice – velmi silný vztah, zánik jednoho způsobí zánik druhého (např. dům – místnost).

Polymorfismus

  • Schopnost pracovat s objekty různého typu jednotně (např. podle společného rozhraní).
  • Umožňuje používat objekty různých tříd pomocí jejich společného nadtypu.

Overloading vs. Overriding

  • Overloading – více metod se stejným jménem, ale různými parametry.
    1. V rámci jedné třídy.
  • Overriding – přepsání metody předka v potomkovi se stejným jménem a parametry.
    1. Umožňuje polymorfismus.
    2. Přepisující metoda může mít méně restriktivní přístup a návratový typ může být podtypem originálu.

Shrnutí OOP přístupů

  • V OOP se program skládá z objektů, které modelují reálné nebo doménové entity.
  • Vztahy mezi objekty a hierarchie tříd tvoří základ pro efektivní návrh softwaru.
  • OOP podporuje modularitu, znovupoužitelnost a snadnější údržbu.

Klíčové koncepty modelování systémů: abstraktní datové typy, mutabilita, imutabilita, rekurze, datové typy v rekurzi.

Abstraktní datový typ (ADT)

  • ADT odděluje abstraktní vlastnosti typu (hodnoty a operace) od konkrétní implementace.
  • ADT je matematický model: množina hodnot + operace nad touto množinou.
  • Umožňuje měnit reprezentaci bez dopadu na uživatele typu.
  • Příklady: `int`, `List`, `Map`, `String`, `Set`, `boolean`.

Typy operací v ADT:

  • Creators – vytvářejí nové instance (`new ArrayList()`)
  • Producers – vytvářejí nové hodnoty z existujících (`concat`, `substring`)
  • Observers – vracejí informace o objektu (`size`, `isEmpty`)
  • Mutators – mění stav objektu (`add`, `remove`)

Vhodný návrh ADT:

  • Má minimum operací, které jdou dobře kombinovat.
  • Každá operace je definována jednoznačně a univerzálně.
  • Měl by být buď generický (List, Map) nebo doménový (BalíčekKaret) – ne kombinace.

Příklady generických ADT:

  • int
    1. Hodnoty: celá čísla
    2. Operace:
      • Creators: `0`, `1`, `-42`
      • Producers: `+`, `-`, `*`, `/`
      • Observers: není třeba – hodnota je přímo dostupná
      • Mutators: nelze – `int` je imutabilní
  • String
    1. Hodnoty: posloupnosti znaků
    2. Operace:
      • Creators: `““`, `”abc”`
      • Producers: `concat`, `substring`, `toUpperCase`
      • Observers: `length`, `charAt`, `isEmpty`
      • Mutators: žádné – `String` je imutabilní
  • List
    1. Hodnoty: uspořádané sekvence hodnot
    2. Operace:
      • Creators: `new ArrayList<>()`
      • Producers: `addAll`, `subList`
      • Observers: `size`, `get`, `contains`
      • Mutators: `add`, `remove`, `set` (u mutabilní implementace)

Příklady doménových ADT:

  • Typ: Balíček karet
    1. Hodnoty: posloupnosti karet
    2. Operace: zamíchej(), rozdej(), přidejNaSpodek(), početKaret()
    3. Rep invariant: žádné duplicity, max 52 karet
  • Typ: Telefonní seznam (Map)
    1. Hodnoty: množina dvojic (jméno, číslo)
    2. Operace: vlož(jméno, číslo), smaž(jméno), hledej(jméno)
    3. Rep invariant: maximálně jedno číslo na jméno

Mutabilita vs Imutabilita

  • Mutabilní objekt – může být po svém vytvoření změněn (`ArrayList`, `Date`).
  • Imutabilní objekt – po vytvoření se nemění (`String`, `Integer`, `LocalDate`).
  • Výhody imutability:
    • Snadnější důkaz korektnosti (nezmění se „pod rukama“).
    • Bezpečnější při paralelním zpracování (thread-safe).
    • Zachování invariant = jednodušší údržba.
  • Problém: *representation exposure* – možnost, že klient modifikuje vnitřní stav objektu.
    • Řešení: použití `final`, zapouzdření, kopírování (`defensive copying`), vlastní kontrola (`checkRep()`).

Invarianty

Invarianta je vlastnost, která je splněna pro jakýkoliv runtime stav programu ve všech jeho stabilních stavech a nezávisí na chování klienta

Pozn. Invariance by měla být zaručena pro volání public metod. Tedy mohou existovat mezistavy, kdy je invariance porušena.

  • Typy invariantů:
    • Rep Invariant (representation invariant) – musí platit pro vnitřní stav objektu, aby byl platný (např. „žádné duplicity v množině“).
    • Konzistenční invarianty systému – například „zákazník nemůže mít záporný zůstatek“.
    • Stavové invarianty – např. „součet dílčích stavů odpovídá celkovému stavu“.
  • Účel invariantů:
    • Pomáhají odhalit chyby (při vývoji i testování).
    • Vyjadřují, co znamená „platný“ stav objektu.
    • Umožňují jednodušší dokazování správnosti (zejména u imutabilních typů).
  • Kontrola invariantů:
    • Může být prováděna explicitně (např. metodou `checkRep()` v implementaci).
    • Vhodná také pro automatizované testování a formální verifikaci.

Rekurze a datové typy v rekurzi

  • Rekurze = definice objektu prostřednictvím sebe sama.
  • Rekurzivní datové typy – typy, které obsahují sebe samé:
    • Např. `List`, `Tree`, `Expression`, `Directory`.
  • Používá se:
    • K definici strukturovaných dat (složené dokumenty, výrazy).
    • Při zpracování stromových a sekvenčních struktur.
  • Výhody:
    • Přirozené a výstižné modelování.
    • Umožňuje definovat operace rekurzivně (např. `size()`, `depth()`, `eval()`).

Shrnutí

  • ADT představují základní stavební bloky modelování dat.
  • Imutabilita a správná práce s invarianty zvyšují bezpečnost a čitelnost systému.
  • Rekurze je klíčový nástroj pro popis složitých typů a operací.

Funkcionánlní programování v Java

Funkce první třídy (first-class functions)

  • Funkce je považována za „objekt první třídy“, pokud ji lze:
    • předat jako parametr jiné funkci,
    • přiřadit do proměnné,
    • vrátit z jiné funkce.
  • Java nepodporuje funkce jako typ, ale využívá funkcionální rozhraní (např. `Function<T,R>`, `Predicate<T>`, `Consumer<T>`).
  • Příklad:
    Predicate<Person> isRetired = p -> p.getAge() > 65;
 

Funkce vyššího řádu (higher-order functions)

  • Funkce, která přijímá jinou funkci jako parametr nebo ji vrací jako výsledek.
  • Java realizuje tento koncept pomocí funkcionálních rozhraní.
  • Příklad filtru:
    public List<Person> filter(List<Person> people, Predicate<Person> p) {
        return people.stream().filter(p).collect(Collectors.toList());
    }

Lambda expressions

  • Zkrácený zápis anonymní funkce.
  • Syntaxe: `(parametry) → výraz`
  • Příklad:
    Comparator<String> comp = (s1, s2) -> s1.length() - s2.length();

Closures

  • Lambda výrazy si mohou „zapamatovat“ hodnoty z okolního kontextu (tzv. *uzávěr*).
  • Hodnota musí být efektivně finální.
  • Příklad:
    int base = 10;
    Function<Integer, Integer> addBase = x -> x + base;

Currying

  • Rozdělení funkce s více parametry na posloupnost funkcí s jedním parametrem.
  • Příklad:
    Function<Integer, Function<Integer, Integer>> add = x -> y -> x + y;
    add.apply(2).apply(3); // vrátí 5

Referential transparency

  • Výraz je referenčně transparentní, pokud jej lze nahradit jeho výsledkem bez změny chování programu.
  • Týká se *pure functions* – bez vedlejších efektů.
  • Výhoda: umožňuje memoizaci (cache výsledků).

Lazy evaluation

  • Výraz se nevyhodnocuje ihned, ale až když je jeho výsledek potřeba.
  • Java podporuje *lazy* chování např. přes `Stream`, `Optional`, `CompletableFuture`.
  • Příklad:
    Stream<Integer> s = Stream.of(1, 2, 3).filter(x -> {
        System.out.println("filtrování " + x);
        return x > 1;
    });
    // kód nad tím nic nevytiskne – evaluace je lazy

Shrnutí rozdílů oproti OOP

| Oblast | Funkcionální přístup | Objektový přístup |
|-|-|-|
| Data | Imutabilní | Mutabilní |
| Exekuce | Libovolné pořadí volání | Definované pořadí volání metod |
| Iterace | Rekurze | Cykly |
| Paralelismus | Snadná podpora díky bezstavovým funkcím | Komplikovanější, vyžaduje synchronizaci |
| Stav | Explicitní (parametry, návraty) | Implicitní (instance proměnné, settery) |

Creational design patterns: factory a abstract factory, builder, prototype, singleton, dependency injection

Singleton

  • Vzor zajišťující, že od dané třídy existuje jen jedna instance.
  • Používá se např. pro přístup ke konfiguraci, logger, správce připojení.
  • Problém: ve vícevláknovém prostředí musí být správně synchronizovaný.
  • Moderní varianta využívá double-checked locking a `volatile`.
  public class Singleton {
      private static volatile Singleton instance;
      private Singleton() {}
      public static Singleton getInstance() {
          if (instance == null) {
              synchronized (Singleton.class) {
                  if (instance == null) {
                      instance = new Singleton();
                  }
              }
          }
          return instance;
      }
  }
 

Factory Method

  • Poskytuje rozhraní pro vytváření objektů, ale samotná implementace tvorby je ponechána podtřídám.
  • Cílem je umožnit instanciaci objektů bez toho, aby klient znal jejich konkrétní typ.
  • Typický v GUI systémech, kde různé platformy poskytují různé implementace komponent.
  abstract class Dialog {
      public void renderWindow() {
          Button okButton = createButton();
          okButton.render();
      }
      public abstract Button createButton();
  }
 
  class WindowsDialog extends Dialog {
      public Button createButton() {
          return new WindowsButton();
      }
  }
 
  class WebDialog extends Dialog {
      public Button createButton() {
          return new HtmlButton();
      }
  }

Abstract Factory

  • Továrna na továrny – vytváří celou „rodinu“ příbuzných objektů bez znalosti jejich konkrétních tříd.
  • Umožňuje snadno měnit konkrétní implementaci celé architektury (např. jiná platforma nebo produkt).
  interface GUIFactory {
      Button createButton();
      Checkbox createCheckbox();
  }
 
  class WinFactory implements GUIFactory {
      public Button createButton() { return new WinButton(); }
      public Checkbox createCheckbox() { return new WinCheckbox(); }
  }

Prototype

  • Vytváření nových objektů klonováním existující instance.
  • Používá se, pokud je konstrukce objektu nákladná nebo složitá.
  • Může jít o:
    • shallow copy - clone() vytvoří novou instanci té samé třídy a nastaví všechny atributy na hodnoty atributů z instance na které voláme clone().
    • deep copy - clone() provede shallow copy a pak clone() i všech navázaných objektů. Naklonuje celý objektový graf. Hloubka kopie může být různá.
  public class Employee implements Cloneable {
      private String name;
      private Address address;
 
      public Employee(String name, Address address) {
          this.name = name;
          this.address = address;
      }
 
      @Override
      public Employee clone() {
          return new Employee(this.name, this.address.clone());
      }
  }

Builder

  • Odděluje konstrukci komplexního objektu od jeho reprezentace.
  • Podporuje fluent interface – volání metod v řetězci.
  • Výhodné při tvorbě objektů s mnoha volitelnými částmi.
  enum EColor {
      RED, WHITE, BLACK
  }
 
  public class House {
      private EColor color;
      private List<Window> windows = new ArrayList<>();
      private List<Wall> walls = new ArrayList<>();
      private Door door;
 
      public void setColor(EColor color) {
          this.color = color;
      }
 
      public void addWindow(Window window) {
          this.windows.add(window);
      }
 
      public void addWall(Wall wall) {
          this.walls.add(wall);
      }
 
      public void setDoor(Door door) {
          this.door = door;
      }
  }
 
  public class HouseBuilder {
      private House house = new House();
 
      public HouseBuilder addWall(){
          house.addWall(new Wall());
          return this;
      }
 
      public HouseBuilder addWindow(){
          house.addWindow(new Window());
          return this;
      }
 
      public HouseBuilder buildDoor() {
          house.setDoor(new Door());
          return this;
      }
 
      public HouseBuilder paint(EColor color){
          house.setColor(color);
          return this;
      }
 
      public House getResult(){
          return house;
      }
  }
  HouseBuilder builder = new HouseBuilder();
  House yourHouse = builder
      .addWall()
      .addWindow()
      .buildDoor()
      .paint(EColor.RED)
      .getResult();

Dependency Injection (DI)

  • Technika PRO VKLÁDÁNÍ ZÁVISLOSTÍ MEZI JEDNOTLIVÝMI KOMPONENTAMI PROGRAMU TAK, ABY JEDNA KOMPONENTA MOHLA POUŽÍVAT DRUHOU, ANIŽ BY NA NI MĚLA V DOBĚ SESTAVOVÁNÍ PROGRAMU REFERENCI.
  • Základní přístupy:
    • Injekce přes atribut (`@Autowired`)
  @Component
  public class Customer {
    @Autowired
    private Person person;
    private int type;
  } 
 
  • Injekce přes setter
  @Component
  public class Customer {
      private Person person;
      @Autowired
      public void setPerson(Person person) {
          this.person = person;
      }
  }
  • Injekce přes konstruktor
  @Component
  public class Customer {
    private Person person;
    @Autowired
    public Customer (Person person) {
      this.person=person;
    }
  }
  • Umožňuje lepší testovatelnost, volnou vazbu a řízení závislostí frameworkem (např. Spring).

Structural design patterns: adapter, proxy, bridge, composite, facade, decorator, flyweight

Adapter

  • Slouží ke sladění rozhraní mezi nekompatibilními třídami.
  • Vytváří třídu, která překládá rozhraní očekávané klientem na rozhraní existující komponenty.
  • Používá se, pokud chceme znovupoužít třídu, ale její rozhraní neodpovídá očekávání aplikace.
   class EuropeanSocket {
       public void connect(String wires) { ... }
   }
 
   interface CzechPlug {
       void zapoj();
   }
 
   class Adapter implements CzechPlug {
       private EuropeanSocket socket;
       public Adapter(EuropeanSocket socket) {
           this.socket = socket;
       }
       public void zapoj() {
           socket.connect("fáze + nulák");
       }
   }

Proxy

  • Objekt, který má stejné rozhraní jako cílový objekt, ale přidává vlastní logiku (např. bezpečnost, logování, cache).
  • Typicky se používá pro řízení přístupu, lazy loading, monitorování atd.
   interface Tower {
       void enter(Wizard wizard);
   }
 
   class TowerProxy implements Tower {
       private Tower tower = new WizardTower();
       public void enter(Wizard wizard) {
           if (wizard.getColor() != Color.GREEN) {
               tower.enter(wizard);
           } else {
               System.out.println("Green wizard is not allowed.");
           }
       }
   }

Facade

  • Vytváří zjednodušené rozhraní pro komplexní podsystém.
  • Klient neřeší detaily volání vnitřních služeb a má přístup jen ke stabilnímu API.
   public class KitchenFacade {
       private Microwave microwave = new Microwave();
       private Fridge fridge = new Fridge();
 
       public void prepareSnack() {
           fridge.open();
           microwave.heat();
           fridge.close();
       }
   }

Decorator

  • Umožňuje dynamicky přidat chování do objektu, aniž bychom měnili jeho třídu.
  • Vytváří se obalové třídy se stejným rozhraním jako původní objekt.
   interface Coffee {
       String getDescription();
       double getCost();
   }
 
   class BasicCoffee implements Coffee {
       public String getDescription() { return "Coffee"; }
       public double getCost() { return 1.0; }
   }
 
   class MilkDecorator implements Coffee {
       private Coffee coffee;
       public MilkDecorator(Coffee coffee) {
           this.coffee = coffee;
       }
       public String getDescription() {
           return coffee.getDescription() + ", milk";
       }
       public double getCost() {
           return coffee.getCost() + 0.5;
       }
   }

Flyweight

  • Minimalizuje spotřebu paměti sdílením společného stavu mezi instancemi objektů.
  • Například `Character` nebo `Particle`, kde se vnitřní reprezentace znovupoužívá.
   class BulletType {
       private String texture;
       public BulletType(String texture) {
           this.texture = texture;
       }
   }
 
   class BulletFactory {
       private static Map<String, BulletType> cache = new HashMap<>();
       public static BulletType get(String texture) {
           return cache.computeIfAbsent(texture, BulletType::new);
       }
   }

Bridge

  • Do root třídy připojím další hiearachii tříd.
  • Umožňuje kombinovat dvě nezávislé hierarchie – např. tvary a jejich vykreslení.

   public interface Color {
       String fill();
   }
 
   public class Blue implements Color {
       @Override
       public String fill() {
           return "Color is Blue";
       }
   }
 
   public class Red implements Color {
       @Override
       public String fill() {
           return "Color is Red";
       }
   }
 
   public abstract class Shape {
       protected Color color;
 
       public Shape(Color color) {
           this.color = color;
       }
 
       public abstract String draw();
   }
 
   public class Square extends Shape {
 
       public Square(Color color) {
           super(color);
       }
 
       @Override
       public String draw() {
           return "Square drawn. " + color.fill();
       }
   }

Srovnání

  • Adapter poskytuje rozdílný interface oproti objektu, který zpřístupňuje, Proxy proskytuje shodný interface
  • Facade a Proxy
    • podobné v tom, že inicializují a poskytují odstínění klienta od komplexních využívaných komplexních objektů
    • Rozdíl v tom, že proxy poskytuje shodný interface jako servisní objekt
  • Decorator a Proxy
    • Podobná struktura, ale rozdílný účel
    • Proxy spravuje životní cyklus servisního objektu
    • Struktura Dekorátoru je řízena klientem
  • Facade definuje nové rozhraní, Adapter spojuje existující rozhraní

Behavioral design patterns

Iterator

  • Odděluje způsob iterace od konkrétní datové struktury.
  • Umožňuje jednotný přístup k prvkům bez znalosti interní reprezentace.
  • Pouze řídí procházení datové struktury pomocí metod next() a hasNext()
   // Iterátor – definuje rozhraní pro iteraci
   public interface Iterator<T> {
       boolean hasNext();
       T next();
   }
 
   // Kontejner – definuje rozhraní, které vrací iterátor
   public interface Container<T> {
       Iterator<T> getIterator();
   }
 
   // Konkrétní implementace kontejneru
   public class NameRepository implements Container<String> {
       private String[] names = { "Anna", "Bob", "Charlie" };
 
       @Override
       public Iterator<String> getIterator() {
           return new NameIterator();
       }
 
       // Interní implementace iterátoru
       private class NameIterator implements Iterator<String> {
           int index = 0;
 
           public boolean hasNext() {
               return index < names.length;
           }
 
           public String next() {
               return hasNext() ? names[index++] : null;
           }
       }
   }
 
   // Použití iterátoru
   public class Demo {
       public static void main(String[] args) {
           NameRepository repo = new NameRepository();
           Iterator<String> it = repo.getIterator();
 
           while (it.hasNext()) {
               System.out.println("Name: " + it.next());
           }
       }
   }

Chain of Responsibility

  • Vytváří řetěz objektů, které mohou zpracovat požadavek.
  • Každý článek rozhoduje, zda požadavek vyřídí nebo předá dál.
   // Abstraktní handler
   abstract class Logger {
       public static int INFO = 1;
       public static int DEBUG = 2;
       public static int ERROR = 3;
 
       protected int level;
       protected Logger nextLogger;
 
       public void setNext(Logger nextLogger) {
           this.nextLogger = nextLogger;
       }
 
       public void logMessage(int level, String message) {
           if (this.level <= level) {
               write(message);
           }
           if (nextLogger != null) {
               nextLogger.logMessage(level, message);
           }
       }
 
       protected abstract void write(String message);
   }
 
   // Konkrétní implementace – konzolový logger
   class ConsoleLogger extends Logger {
       public ConsoleLogger(int level) {
           this.level = level;
       }
 
       protected void write(String message) {
           System.out.println("Standard Console::Logger: " + message);
       }
   }
 
   // Konkrétní implementace – souborový logger
   class FileLogger extends Logger {
       public FileLogger(int level) {
           this.level = level;
       }
 
       protected void write(String message) {
           System.out.println("File::Logger: " + message);
       }
   }
 
   // Konkrétní implementace – chybový logger
   class ErrorLogger extends Logger {
       public ErrorLogger(int level) {
           this.level = level;
       }
 
       protected void write(String message) {
           System.out.println("Error Console::Logger: " + message);
       }
   }
 
   // Klient, který sestaví řetězec a provede logování
   public class ChainPatternDemo {
       private static Logger getChainOfLoggers() {
           Logger errorLogger = new ErrorLogger(Logger.ERROR);
           Logger fileLogger = new FileLogger(Logger.DEBUG);
           Logger consoleLogger = new ConsoleLogger(Logger.INFO);
 
           errorLogger.setNext(fileLogger);
           fileLogger.setNext(consoleLogger);
 
           return errorLogger;
       }
 
       public static void main(String[] args) {
           Logger loggerChain = getChainOfLoggers();
 
           loggerChain.logMessage(Logger.INFO, "This is an informational message.");
           loggerChain.logMessage(Logger.DEBUG, "This is a debug level message.");
           loggerChain.logMessage(Logger.ERROR, "This is an error message.");
       }
   }

Strategy

  • Umožňuje měnit algoritmus nebo chování za běhu.
  • Klient deleguje operaci na zvolenou strategii.
  • Používá se, když pro realizaci jednoho tasku chceme flexibilně přepínat mezi různými algoritmy
   // Společné rozhraní pro strategii
   public interface PoliceStrategy {
       void checkDriver(Driver driver);
   }
 
   // Jednodušší strategie
   public class NicePolice implements PoliceStrategy {
       @Override
       public void checkDriver(Driver driver) {
           System.out.println("You're okay, have a nice day!");
       }
   }
 
   // Přísnější strategie
   public class HardPolice implements PoliceStrategy {
       @Override
       public void checkDriver(Driver driver) {
           if (driver.getAlcoholLevel() > 0) {
               System.out.println("You are under arrest!");
           } else {
               System.out.println("You're free to go.");
           }
       }
   }
 
   // Kontext používající zvolenou strategii
   public class PoliceOfficer {
       private PoliceStrategy strategy;
 
       public PoliceOfficer(PoliceStrategy strategy) {
           this.strategy = strategy;
       }
 
       public void setStrategy(PoliceStrategy strategy) {
           this.strategy = strategy;
       }
 
       public void performCheck(Driver driver) {
           strategy.checkDriver(driver);
       }
   }

Visitor

  • Odděluje algoritmus od struktury dat.
  • Umožňuje přidat nové operace bez změny datové struktury.
   public interface ComputerPart {
       void accept(Visitor v);
   }
 
   public class Mouse implements ComputerPart {
       public void accept(Visitor v) {
           v.visit(this);
       }
   }
 
   public class DisplayVisitor implements Visitor {
       public void visit(Mouse mouse) {
           System.out.println("Displaying Mouse.");
       }
   }

Observer

  • Umožňuje reakcí více objektů (observers) na změnu stavu jiného objektu (subject).
  • Subject si spravuje seznam observerů a při změně je notifikuje.
   // Rozhraní pozorovatele
   public abstract class Observer {
       protected Subject subject;
       public abstract void update();
   }
 
   // Třída Subject s registrací a notifikací
   public class Subject {
       private List<Observer> observers = new ArrayList<>();
       private int state;
 
       public int getState() {
           return state;
       }
 
       public void setState(int state) {
           this.state = state;
           notifyAllObservers();
       }
 
       public void attach(Observer observer) {
           observers.add(observer);
       }
 
       private void notifyAllObservers() {
           for (Observer o : observers) {
               o.update();
           }
       }
   }
 
   // Konkrétní pozorovatelé
   public class HexObserver extends Observer {
       public HexObserver(Subject subject) {
           this.subject = subject;
           subject.attach(this);
       }
 
       public void update() {
           System.out.println("Hex: " + Integer.toHexString(subject.getState()));
       }
   }
 
   public class BinaryObserver extends Observer {
       public BinaryObserver(Subject subject) {
           this.subject = subject;
           subject.attach(this);
       }
 
       public void update() {
           System.out.println("Binary: " + Integer.toBinaryString(subject.getState()));
       }
   }
 
   public class OctalObserver extends Observer {
       public OctalObserver(Subject subject) {
           this.subject = subject;
           subject.attach(this);
       }
 
       public void update() {
           System.out.println("Octal: " + Integer.toOctalString(subject.getState()));
       }
   }
 
   // Ukázka použití
   public class ObserverDemo {
       public static void main(String[] args) {
           Subject subject = new Subject();
 
           new HexObserver(subject);
           new OctalObserver(subject);
           new BinaryObserver(subject);
 
           System.out.println("First state change: 15");
           subject.setState(15);
 
           System.out.println("Second state change: 10");
           subject.setState(10);
       }
   }

Template Method

  • Definuje kostru algoritmu v nadtřídě, variantní části jsou ponechány podtřídám.
  • Používá se, když je potřeba opakovat strukturu algoritmu, ale některé kroky se liší.
   abstract class Game {
       final void play() {
           initialize();
           startPlay();
           endPlay();
       }
       abstract void initialize();
       abstract void startPlay();
       abstract void endPlay();
   }

State

  • Modeluje stav systému jako objekt.
  • Každý stav má specifické chování a určuje přechod do jiných stavů.
   player.setState(new ReadyState());
   player.play();  // deleguje na aktuální stav

Memento

  • Umožňuje vrátit objekt do předchozího stavu.
  • Využívá se pro `undo`, `redo` funkce.
   caretaker.saveState(originator.createMemento());
   originator.setState("nový stav");
   originator.restore(caretaker.getLastSavedState());

Interpreter

  • Vyhodnocuje výrazy v definovaném jazyce (např. matematický jazyk).
  • Každý prvek jazyka má vlastní třídu.
   Expression exp = new Plus(
       new Variable("w"),
       new Minus(
           new Variable("x"),
           new Variable("z")
       )
   );
   Map<String, Integer> context = Map.of("w", 6, "x", 30, "z", 8);
   int result = exp.evaluate(context);  // výsledek: 6 + (30 - 8)

Datové struktury a patterny: lazy loading, object pool, cache map, filter, reduce pattern

Specifikace, návrhy specifikací, web API, Apiary, Swagger, GraphQL

Navigation

Playground

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