Oto przykład, jak przerobiliśmy wczytywacza według wzorca projektowego template method.
Stworzyliśmy abstrakcyjną klasę OgolnyWczytywacz – zajmuje się ona tylko odpowiednim obsługiwaniem wyjątków i zamknięciem strumienia:
import java.io.IOException; import java.io.InputStream; public abstract class OgolnyWczytywacz { public OgolnyWczytywacz() { super(); } protected abstract Object dzialajNaStrumieniu(InputStream fis) throws Exception; protected abstract InputStream otworzStrumien() throws IOException; public Object dzialaj() throws WczytywanieDanychException { InputStream fis = null; try { fis = otworzStrumien(); return dzialajNaStrumieniu(fis); } catch (Exception e) { throw new WczytywanieDanychException("coś poszło nie tak przy wczytywaniu pliku", e); } finally { if (fis != null) { try { fis.close(); } catch (IOException e) { } } } } }
Stworzyliśmy też dziedziczącą po OgolnymWczytywaczu klasę Wczytywacz – w niej nie musieliśmy już bawić się z wyjątkami:
import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.Reader; public class Wczytywacz extends OgolnyWczytywacz { @Override protected InputStream otworzStrumien() throws IOException { File f = new File("c:\\Users\\admin\\Desktop\\psobolewski\\nic\\sprzedaz.csv"); return new FileInputStream(f); } @Override protected Object dzialajNaStrumieniu(InputStream fis) throws Exception { Zamowienie[] zamowienia = new Zamowienie[10000]; Reader isr = new InputStreamReader(fis, "utf8"); BufferedReader br = new BufferedReader(isr); String linia; int licznik = 0; br.readLine(); while ((linia = br.readLine()) != null) { String[] pola = linia.split(";"); if (pola.length >= 8) { zamowienia[licznik] = new Zamowienie(pola[0], pola[1], pola[2], pola[3], pola[4], pola[5], pola[6], pola[7]); licznik++; } } return zamowienia; } }
Ponieważ w nowej klasie Wczytywacz metoda dzialaj nie jest już statyczna, korzystać z niej trzeba tak:
public class GeneratorRaportow { public static void main(String[] args) { try { OgolnyWczytywacz w = new Wczytywacz(); Zamowienie[] zamowienia = (Zamowienie[]) w.dzialaj(); for (Zamowienie z: zamowienia) { System.out.println(z); } } catch (WczytywanieDanychException e) { System.out.println("nie udało się wczytać danych"); } } }
Żeby przekonać się, że OgolnyWczytywacz rzeczywiście ułatwia działania ze strumieniami, napisaliśmy program wczytujący ze strony WWW listę liczb całkowitych i podsumowujących ją. Składa się on z klasy WczytywaczLiczbZUrla:
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.URL; public class WczytywaczLiczbZUrla extends OgolnyWczytywacz { @Override protected Object dzialajNaStrumieniu(InputStream fis) throws Exception { BufferedReader br = new BufferedReader(new InputStreamReader(fis)); String linia; int suma = 0; while ((linia = br.readLine()) != null) { suma += Integer.valueOf(linia); } return Integer.valueOf(suma); } @Override protected InputStream otworzStrumien() throws IOException { return new URL("http://psobolewski.students.alx.pl/nic/liczby.txt").openStream(); } }
…oraz takiego kodu, który korzysta z tej klasy:
WczytywaczLiczbZUrla w = new WczytywaczLiczbZUrla(); try { int wynik = (Integer) w.dzialaj(); System.out.println(wynik); } catch (Exception e) { // ... tu można by coś zrobić }
ćwiczenie
Zachęcam do przerobienia klasy OgolnyWczytywacz tak, żeby była generyczna, parametryzowana typem zwracanym przez metodę dzialaj.