===== OMO - 3. cvičení - Dědičnost, skládání ===== Na třídách //Stack// a //SmartStack// by měla být vidět výhoda dědičnosti. Stačilo nám překrýt jen metodu ''push'', resp. přidat ještě privátní metodu na zvětšení vnitřního pole, a máme lepší zásobník. Ostatní metody můžeme nechat beze změny a zásobník bude fungovat. ===== Stack.java ===== package stack; import java.util.EmptyStackException; public class Stack { /* * Toto byl nebezpecny napad. * Proc? * protected int capacity; * Tady to neni tak vyrazne, ale v druhem priklade uz bude */ /* * Pole na ukladani hodnot */ protected int [] storage; /* * Index prvniho volneho prvku pole */ protected int index; /** * Konstruktor * @param cap kapacita zasobniku */ public Stack(int cap){ storage = new int [cap]; index = 0; } /** * Konstruktor s vychozi kapacitou (1000) */ public Stack(){ this(1000); } /** * Vlozi prvek na vrchol zasobniku * @param element prvek, ktery ma byt ulozen */ public void push(int element){ if (index >= getCapacity()){ throw new StackFullException(getCapacity()); } storage[index] = element; index ++; } /** * Vyjme prvek z vrcholu zasobniku a vrati jej * @return vyjmuty prvek */ public int pop(){ if (index <= 0){ throw new EmptyStackException(); } index --; return storage[index]; } /** * Vrati celkovou kapacitu zasobniku * @return celkovou kapacitu zasobniku */ public int getCapacity(){ return storage.length; } /** * Vraci obsazenost zasobniku * @return pocet prvku na zasobniku */ public int getCount(){ return index; } } ===== SmartStack.java ===== Vylepšený zásobník. Všimněte si, že zde by udržování kapacity ve speciální proměnné už mohlo přinést problémy. Pokud bychom zapomněli aktualizovat kapacitu nebo ji změnili nikoliv v souladu s délkou úložného pole, dostali bychom náš zásobník do nekonzistentního stavu. Zde je samozřejmé všechny proměnné uchovat nepřístupné pro uživatele třídy. package stack; import java.util.Arrays; public class SmartStack extends Stack { /** * Konstuktor zasobniku s vychozi pocatecni kapacitou (1000) */ public SmartStack() { super(); } /** * Konstruktor s volitelnou pocatecni kapacitou * @param cap pocatecni kapacita zasobniku */ public SmartStack(int cap) { super(cap); } /** * Zvetsi kapacitu zasobniku o inkrement * @param increment inkrement zvetseni kapacity zasobniku */ protected void enlargeCapacity(int increment) { storage = Arrays.copyOf(storage, storage.length + increment); System.out.println("Enlarging to: " + storage.length); } /** * Prekryte push, pokud vlozeni prvku selze, zvetsi zasobnik * a zkusi prvek vlozit znovu. * @param element vkladany prvek */ @Override public void push(int element) { try { super.push(element); } catch (StackFullException ex) { enlargeCapacity(getCapacity()); super.push(element); } } } ===== Stack2.java ===== Na třídě Stack2 naopak ilustrujeme opačný případ. Pro vytvoření zásobníku použijeme třídu //ArrayList//, což je implementace dynamicky se natahujícího pole. Dědění by v tomto případě "vylepšilo" zásobník o dvě metody, ''push'' a ''pop'', ale nechalo by přístupné všechny metody, které poskytoval //ArrayList//, takže bychom mohli při použití zásobníku "podvádět" přístupem přes tyto metody. Překrýt všechny metody a nastavit je na private nelze - Java to nedovolí. Modifikátory jsou informací pro překladač a kdyby tohle povolil, tak by to v runtimu šlo obejít. Řešení je "zabalit" //ArrayList// do naší třídy a zprostředkovat jen operace, které chceme. Konceptu, kdy si funkčnost objektu poskládáme z jiných, se překvapivě říká skládání. package stack; import java.util.ArrayList; public class Stack2 { private ArrayList storage = new ArrayList(); public void push(int element){ storage.add(new Integer(element)); } public int pop(){ return storage.remove(storage.size()-1).intValue(); } public int getCount(){ return storage.size(); } } ===== Main.java ===== package stack; public class Main { public static void main (String [] args){ Stack2 stack = new Stack2(); /* * Zkuste vymenit * Stack stack = new Stack(4); * Stack stack = new SmartStack(4); */ stack.push(1); stack.push(2); stack.push(3); stack.push(4); stack.push(5); stack.push(6); stack.push(7); while (stack.getCount()>0){ System.out.println(stack.pop()); } } }