Warning
This page is located in archive.

Osnova

  • diagram tříd - třídy, atributy, metody, asociace, kardinalita asociací
  • hierarchické vztahy - generalizace, podtyp/nadtyp, dědičnost
  • diagramy stavů - stavy, přechody, události, spouštěcí podmínky (guards), akce
  • diagram sekvencí
  • diagram komunikace
  • návrhové vzory - tovární metoda (factory method), jedináček (singleton), abstraktní továrna (abstract factory), prototyp (prototype), stav/strategie (state/strategy), kompozit (composite), interpretr (interpreter), návštěvník (visitor)
  • double dispatch

Příklady na návrhové vzory

  • Třída Rectangle reprezentuje obdélník, třída Square čtverec. Napište tovární metodu Shape getShape(int height, int width), která vrátí instanci vhodné třídy. Vhodné konstruktory si domyslete. Tip: použijte tovární metodu.
  • Fronta se od zásobníku liší tím, že metoda pop vrací nejstarší prvek, zatímco u zásobníku ta samá metoda vrací prvek nejmladší. Naimplementujte třídu Container, která se chová jako fronta nebo jako zásobník podle toho, co si uživatel zvolí. Tip: při implementaci využijte návrhový vzor state nebo strategy.
  • Naimplementujte abstraktní továrnu: třídy továren by měly být Zerg, Protoss a Terran, jejich společné rozhraní Race s tovární metodou Unit getUnit(), statická metoda vracející abstraktní továrnu by měla být ve třídě Game a jmenovat se getMyRace().
  • Napište třídy implementující návrhový vzor interpret, který by byl schopen interpretovat níže uvedený kousek kódu.

a = 10;
b = a;
c = b + 1;
print c;

  • Níže uvedený kód implementuje návrhový vzor. Který?

interface A {
    void f(D d);
}
 
class B implements A {
    public void f(D d) {
        d.g(this);
    }
}
 
class C implements A {
    public void f(D d) {
        d.h(this);
    }
}
 
interface D {
    void g(B b);
    void h(C c);
}

  • Třída List reprezentuje seznam čísel. Upravte kód níže tak, aby šlo ve spojovém seznamu kromě instancí třídy Chunk libovolně střídat také instance tříd Node a Pair (upravit budete muset všechny třídy, neřešte změny v kódu, který nevidíte).

class List {
    Chunk first;
 
    /* kod */
}
 
class Chunk {
    int[] contents = new int[10];
    int length;
    Chunk next;
 
    /* kod */
}
 
class Node {
    int contents;
    Node next;
 
    /* kod */
}
 
class Pair {
    int first;
    int second;
    Pair next;
 
    /* kod */
}

  • Do třídy Cell dopište podporu návrhového vzoru jedináček (singleton). Dejte si pozor, aby tato podpora skutečně zajistila, že nepůjde vytvořit víc než jedna instance Cell.

class Cell {
    int contents;
 
    void set(int c) { contents = c; }
    int get() { return contents; }
}

  • Navrhněte strukturu tříd (tzn. rozhraní, třídy, jejich instanční proměnné a hlavičky metod) odpovídající návrhovému vzoru interpretr, která by byla schopná interpretovat následující kód:

begin
  a = 8
  b = 9
  r = 0
  while a > 0 do begin
    r = r + b
    a = a – 1
  end
end

  • Napište kód implementující návrhový vzor abstract factory: továrna by měla být schopná vracet BlueCircle a BlueSquare nebo RedCircle a RedSquare v závislosti na tom, jestli je ve stavu blue nebo red.
  • Změňte níže uvedený kód tak, abyste se zbavili použití operátoru instanceof. Pokud chcete, můžete změnit také design souvisejícího kódu. Inspirujte se návrhovým vzorem visitor/double dispatchem, vyhněte se řešením založeným na metodách typu getTypeId.

void f(Vehicle v) {
    if (v instanceof Car) v.g();
    else v.h();
}

  • Třída InfiniteArray reprezentuje nekonečné pole (s indexy od nuly výš), které je na počátku celé naplněné nulami. Má dvě možné reprezentace – pole, které se automaticky “prodlužuje”, nebo spojový seznam dvojic (index, hodnota). Napište implementaci třídy InfiniteArray, která mezi těmito dvěma reprezentacemi přepíná – pokud počet nulových prvků v intervalu (0, nejvyšší index s nenulovým prvkem) klesne pod třetinu, přepne na reprezentaci polem, pokud naopak vzroste nad dvě třetiny, přepne na reprezentaci spojovým seznamem. Při implementaci použijte návrhový vzor state/strategy.

class InfiniteArray {
    /* atributy */
    void set(int index, int value) { /* kod */ }
    int get(int index) { /* kod */ }
}

  • Do rozhraní Zajic a tříd Bob a Bobek doplňte podporu pro návrhový vzor visitor a využijte ji v metodě Vecernicek.zacni tak, abyste se zbavili použití operátoru instanceof.

interface Zajic {
    void vstavej();
    void spi();
}
 
class Bob implements Zajic {
    public void vstavej() { /* kod */ }
    public void spi() { /* kod */ }
}
 
class Bobek implements Zajic {
    public void vstavej() { /* kod */ }
    public void spi() { /* kod */ }
}
 
class Vecernicek {
    void zacni(Zajic z) {
        if (z instanceof Bob) z.vstavej();
        if (z instanceof Bobek) z.spi();
    }
}

  • Instance třídy Fraction jsou imutabilní – během svého života nemění svoji hodnotu. Napište tovární metodu Fraction get(int n, int d), která pro stejné hodnoty n a d vrací stejné instance. Pokud chcete, můžete použít třídu HashMap.

class Fraction {
    int nominator, denominator;
 
    Fraction(int n, int d) {
        nominator = n;
        denominator = d;
    }
 
    Fraction times(Fraction f) {
        return new Fraction( nominator * f.nominator,
                         denominator * f.denominator);
    }
}

  • Napište třídy implementující návrhový vzor interpret, který by byl schopen interpretovat níže uvedený kousek kódu.

a = 10;
b = a;
c = b + 1;
print c;

  • Níže uvedený kód implementuje návrhový vzor. Který?

interface A {
    B getB();
    C getC();
}
 
interface B {}
 
interface C {}
 
class D implements B {}
class E implements B {}
 
class F implements C {}
class G implements C {}
 
class H implements A {
    public B getB() {
        return new D();
    }
 
    public C getC() {
        return new F();
    }
}
 
class I implements A {
    public B getB() {
        return new E();
    }
 
    public C getC() {
        return new G();
    }
}
 
class J {
    A a = new H();
 
    void h() {
        a = new H();
    }
 
    void i() {
        a = new I();
    }
 
    A getA() {
        return a;
    }
}

  • Naprogramujte třídu Fraction reprezentující zlomek. Použijte návrhový vzor kompozit tak, aby v čitateli i jmenovateli zlomku mohla být jak reálná, tak komplexní třída.
  • Naprogramujte tovární metodu static Number getNumber(int re, int im), která bude pro reprezentaci stejných čísel vracet stejné objekty (tzn. například volání getNumber(1, 2) pokaždé vrátí ukazatel na stejnou instanci). Pokud chcete, můžete použít HashMap nebo jinou kolekci.
  • Do kódu níže dopište podporu pro visitora a visitora, který dané dvě instance sečte.

interface Number {
    int getReal();
    int getImaginary();
}
 
class Real implements Number {
    int value;
 
    Real(int v) {
        value = v;
    }
 
    public int getReal() {
        return value;
    }
 
    public int getImaginary() {
        return 0;
    }
}
 
class Complex implements Number {
    int re, im;
 
    Complex(int r, int i) {
        re = r;
        im = i;
    }
 
    public int getReal() {
        return re;
    }
 
    public int getImaginary() {
        return im;
    }
}

  • Třídy Vladimir a Iljic implementují interface Lenin. Napište tovární metodu, která pomocí abstract factory při prvních pěti voláních vrátí novou instanci třídy Vladimir a pak už jen instance třídy Iljic.
  • V JDBC se spojení s databází naváže pomocí kódu napsaného níže. Instance vrácená voláním createStatement implementuje rozhraní Statement, ale její skutečnou třídu JDBC určí podle řetězce zadaného jako parametr metody getConnection. Který návrhový vzor (z těch, které jsme se učili) je tomu nejblíže a proč?

Connection con = DriverManager.getConnection
    ("jdbc:myDriver:wombat","myLogin","myPassword");
Statement stmt = con.createStatement();

  • Uživatel vašeho matematického systému chce ve svých programech psát zápisy typu A + B (sjednocení dvou množin), A – B (množinový rozdíl) a A * B (kartézský součin dvou množin). Navrhněte strukturu tříd implementující návrhový vzor interpretr, která by tyto operace byla schopná realizovat.
  • V kódu níže je neoptimalita související s tím, že všechny třídy implementující rozhraní Sort nemají žádné instanční proměnné a jsou tudíž bezestavové. Zlepšete ho. Tip: spojte tovární metodu s návrhovým vzorem stav.

class Sorter {    
    static void bubbleSort(int[] array) {
        /* kod */
    }
 
    static void quickSort(int[] array) {
        /* kod */
    }
 
    static void heapSort(int[] array) {
        /* kod */
    }
 
    Sort s = new BubbleSort();
 
    void setPreferredSortType(int type) {
        if (type == 1) s = new BubbleSort();
        if (type == 2) s = new QuickSort();
        if (type == 3) s = new HeapSort();
    }
 
    void sort(int[] array) {
        s.sort(array);
    }
}
 
interface Sort {
    void sort(int[] array);
}
 
class BubbleSort implements Sort {
    public void sort(int[] array) {
        Sorter.bubbleSort(array);
    }
}
 
class QuickSort implements Sort {
    public void sort(int[] array) {
        Sorter.quickSort(array);
    }
}
 
class HeapSort implements Sort {
    public void sort(int[] array) {
        Sorter.heapSort(array);
    }
}

  • Třída Triangle implementuje návrhový vzor state se stavy pravoúhlý, ostroúhlý a tupoúhlý. Naimplementujte do této třídy podporu pro návrhový vzor visitor, která se bude rozhodovat podle stavu dané instance.

class Triangle {
    TriangleState s;
 
    void visit(TriangleVisitor v) { /* … */ }
 
    /* ... */
}
 
interface TriangleVisitor {
    void visitRectangular(Triangle t);
    void visitObtuse(Triangle t);
    void visitAcute(Triangle t);
}

courses/a4b33si/prednaskove_materialy/objektove_modelovani.txt · Last modified: 2013/10/04 13:02 (external edit)