===== 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());
}
}
}