Omówienie aplikacji domowej – część II
Czas na omówienie kolejnej części aplikacji domowej z tygodnia 4 – czyli kolej na refaktoryzację serwisów.
Singletony
Kolejnym zadaniem w kolejce jest stworzenie singletonów z naszych serwisów – no to do dzieła.
Przypominam, że testy testujące serwisy możesz usunąć, ponieważ struktura klasy całkiem się zmienia, o czym powiem na koniec omawiania.
ProductServiceImpl
Na poczatku musimy usunąć listę produktów – nie będzie nam już potrzebna, ponieważ zastąpi ją klasa ProductDao odpowiedzialna za relację z bazą danych, którą właśnie symulowała owa lista.
Czyli musimy zostawić konstruktor bezparametrowy – prywatny – oraz dodać metodę getInstance, aby nasza klasa była singletonem.
private static ProductServiceImpl instance = null; private ProductServiceImpl() { } public static ProductServiceImpl getInstance() { if (instance == null) { instance = new ProductServiceImpl(); } return instance; }
Dzięki temu, metoda getInstance zawsze zwróci ten sam obiekt.
UserServiceImpl
To samo robimy z klasą UserServiceImpl, wygląda ona identycznie jak jej poprzednik.
private static UserServiceImpl instance = null; private UserServiceImpl() { } public static UserServiceImpl getInstance() { if (instance == null) { instance = new UserServiceImpl(); } return instance; }
I w taki o to sposób i ta klasa została singletonem. 😉
DAO
Skoro usunęliśmy listy z serwisów to musimy dodać pola odpowiedzialne za relację z bazą danych.
W przypadku UserServiceImpl wygląda to tak:
private UserDao userDao = UserDaoImpl.getInstance();
W końcu UserDao jest również singletonem.
No i jeszcze ProductServiceImpl:
private ProductDao productDao = new ProductDaoImpl("products.data", "PRODUCT");
Póki co ProductDaoImpl nie jest singletonem, dlatego póki co na “sztywno” ustawiamy nazwę pliku oraz typ produktu.
Walidacja
Skoro wczesniej stworzyliśmy UserValidator to warto byłoby go użyć własnie w UserServiceImpl, dlatego musimy również dodać walidator jako pole w klasie.
private UserValidator userValidator = UserValidator.getInstance();
Dzięki temu, w całej klasie możemy teraz korzystać z wcześniej stworzonego walidatora.
Skoro jest już utworzony walidator to musimy go użyć w metodzie addUser – jeśli wszystko będzie okej to użytkownik zostanie dodany do pliku, jeśli zaś nie to zostanie rzucony odpowiedni wyjątek z klasy walidującej – UserValidator.
public void addUser(User user) throws IOException, UserShortLengthPasswordException, UserLoginAlreadyExistException, UserShortLengthLoginException { if (userValidator.isValidate(user)) { userDao.saveUser(user); } }
Może nasuwać się jedno pytanie – czy walidacji nie można być zrobić od razu w serwisie, albo w klasie Dao?
Jednak od razu chcę przypomnieć Ci jedną z poprzednich lekcji, w której mówiłem Ci o zasadzie jednej odpowiedzialności. Dzieląc aplikację w taki sposób jaki Ci pokazałem kod będzie czytelniejszy, ponieważ zachowujemy zasadę, gdzie każda klasa jest odpowiedzialna za określoną czynność.
Singleton UserDao
Szóstym zadaniem jest utworzenie singletonu z klasy UserDaoImpl. Tak naprawdę w zadaniu 5 wykorzystałem już metodę getInstance, która nie powinna jeszcze istnieć, jednak przypadkiem zamieniłem kolejnością zadania i wyszły takie kwiatki.
Jednak UserDaoImpl powinna mieć konstruktor prywatny i oczywiście metodę publiczną getInstance, która będzie zwracać jeden, konkretny obiekt.
private static final String fileName = "users.data"; private static UserDaoImpl instance = null; private UserDaoImpl() { try { FileUtils.createNewFile(fileName); } catch (IOException e) { System.out.println("Error with file path"); // exit zamyka całą aplikację System.exit(-1); } } public static UserDaoImpl getInstance() { if (instance == null) { instance = new UserDaoImpl(); } return instance; }
Podsumowanie
Chciałbym zatrzymać Cię na chwilę po tym podsumowaniu, aby trochę popatrzeć na to co zrobiliśmy.
Spójrz, że im większa jest nasza aplikacja to jej stopień skomplikowania rośnie. Trzeba myśleć o wielu rzeczach i niektóre rzeczy się mogą popsuć tworząc inny fragment kodu. Uczulam Cię na to, że programowanie to nie tylko pisanie kodu, ale również jego refaktoryzacja oraz wyszukiwanie błędu.
Na początku tworzenia klasy ProductDao nie zastanawialiśmy się dokładnie jak będzie odbywało się zapisywanie oraz wczytywanie produktów z pliku. Przez to, że mało czasu zostało poświęcone na początku planowania aplikacji to teraz trzeba poświęcić jeszcze więcej czasu, aby to naprawić. I zrobić to dobrze. Dlatego w następnych tygodniach będziemy naprawiać właśnie tą klasę. 😉
Aktualny stan aplikacji możesz zobaczyć tutaj.
Kiedy dalsza część? 🙂
Niestety miałem dużo zaległości do nadrobienia po urlopie, jednak część o fasadach pojawi się na pewno jutro. 😉