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.