* SOLID principy:
* DRY (Don't Repeat Yourself)
Interface použijeme, jestliže:
Abstraktní třídu použijeme, jestliže:
Typy operací v ADT:
Vhodný návrh ADT:
Příklady generických ADT:
Příklady doménových ADT:
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.
Predicate<Person> isRetired = p -> p.getAge() > 65;
public List<Person> filter(List<Person> people, Predicate<Person> p) { return people.stream().filter(p).collect(Collectors.toList()); }
Comparator<String> comp = (s1, s2) -> s1.length() - s2.length();
int base = 10; Function<Integer, Integer> addBase = x -> x + base;
Function<Integer, Function<Integer, Integer>> add = x -> y -> x + y; add.apply(2).apply(3); // vrátí 5
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
| 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) |
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; } }
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(); } }
interface GUIFactory { Button createButton(); Checkbox createCheckbox(); } class WinFactory implements GUIFactory { public Button createButton() { return new WinButton(); } public Checkbox createCheckbox() { return new WinCheckbox(); } }
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()); } }
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();
@Component public class Customer { @Autowired private Person person; private int type; }
@Component public class Customer { private Person person; @Autowired public void setPerson(Person person) { this.person = person; } }
@Component public class Customer { private Person person; @Autowired public Customer (Person person) { this.person=person; } }
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"); } }
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."); } } }
public class KitchenFacade { private Microwave microwave = new Microwave(); private Fridge fridge = new Fridge(); public void prepareSnack() { fridge.open(); microwave.heat(); fridge.close(); } }
* Účel:
* Struktura:
* Výhody:
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(""); } }
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; } }
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); } }
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(); } }
// 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()); } } }
// 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."); } }
// 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); } }
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."); } }
// 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); } }
abstract class Game { final void play() { initialize(); startPlay(); endPlay(); } abstract void initialize(); abstract void startPlay(); abstract void endPlay(); }
// Rozhraní pro 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't 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. } }
// Memento – reprezentuje uložený stav public class Memento { 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 } }
// Rozhraní pro výraz public interface Expression { int interpret(Map<String, Integer> context); } // Terminální výraz – proměnná public class Variable implements Expression { private String name; 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); // 5 + (10 - 3) = 12 System.out.println("Výsledek: " + result); } }
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(); } }
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);
* Vzor, který ukládá data, která se často opakovaně používají.
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"));
List<String> names = people.stream() .map(Person::getName) .collect(Collectors.toList());
// 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);
List<Person> fromPraha = people.stream() .filter(p -> p.getCity().equals("Praha")) .collect(Collectors.toList());
List<String> sortedNames = people.stream() .filter(p -> p.getCity().equals("Praha")) .map(Person::getName) .sorted() .collect(Collectors.toList());
= Formální popis toho, jak se má komponenta v systému chovat
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."
Změna specifikace - silná vs. slabá
S2 je silnější nebo stejná jako S1 pokud:
=> můžeme nahradit S1 za S2 bez ovlivnění stávajících klientů
Přesnost popisu specifikace
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í preferovanější)
Testování - testy musí splňovat podmínky specifikace, testy nesmí být podřízeny implementaci, ale výhradně specifikaci rozhraní
= architektonický styl pro návrh webových API (nemusí být nutně vázaný na HTTP protokol)
Existují různé úrovně implementace:
Web API
= api na webovém serveru nebo klientu
SOAP (Simple Object Access Protocol)
REST API
GraphQL
Open API
Swagger
na datové struktury se v rámci zpráv odkazuje pomocí REF - uri
APIARY