Aplikacja domowa – zadanie

Nareszcie zakończył się tydzień piąty kursu – czas na duży refaktor naszej aplikacji oraz utrwalenie sobie kilku zagadnień z tego tygodnia. Lepiej nie przedłużać, tylko przejść od razu do rzeczy bo pracy jest naprawdę wiele. 😉

Nie zniechęcaj się – tak często wygląda praca przy projekcie, czasami trzeba “zaorać” sporo kodu, aby móc stworzyć jeszcze lepszej kodu o lepszej architekturze.

Interfejsy

Interfejsy zostały lekko przebudowane, aktualnie wyglądają one tak:

ProductDao

public interface ProductDao {

    void saveProduct(Product product) throws IOException;
    void saveProducts(List<Product> products) throws FileNotFoundException;

    void removeProductById(Long productId) throws IOException;
    void removeProductByName(String productName) throws IOException;

    List<Product> getAllProducts() throws IOException;

}

UserDao

public interface UserDao {

    void saveUser(User user) throws IOException;
    void saveUsers(List<User> users) throws FileNotFoundException;

    void removeUserById(Long userId) throws IOException;
    void removeUserByLogin(String login) throws IOException;

    List<User> getAllUsers() throws IOException;
    
}

ProductService

public interface ProductService {
    List<Product> getAllProducts() throws IOException;
    Integer getCountProducts() throws IOException;
    Product getProductByProductName(String productName) throws IOException;

    boolean isProductOnWarehouse(String productName);
    boolean isProductExist(String productName);
    boolean isProductExist(Long productId);

    boolean saveProduct(Product product);
}

UserService

public interface UserService {
    boolean addUser(User user);

    void removeUserById(Long userId) throws IOException;

    List<User> getAllUsers() throws IOException;
    User getUserById(Long userId) throws IOException;
    User getUserByLogin(String login) throws IOException;

    boolean isCorrectLoginAndPassword(String login, String password);
}

Niektóre funkcje z interfejsów zniknęły, w niektórych zmieniły się argument albo typ zwracany. Na podstawie aktualnych interfejsów przebuduj serwisy oraz dao.

Product type

O ile wcześniej był problem z wczytywaniem produktów to teraz znalazłem na to idealne rozwiązanie.

Każdy model – czyli Product, Cloth Booth niech posiada w sobie ProductType – u mnie są to dokładnie duże litery: P, C, B.

Utworzone productType jako statyczne stałe w klasie użyj w metodzie toString podczas budowania Stringa.

ProductParser

Skoro zmieniamy zapisywany ciąg znaków produktów to trzeba również zmienić lekko metodę parsowania. Na podstawie wczytanego znaku product type uruchom odpowiedni parser.

Pamiętaj, że poprzednie parsery zaczynały od 0 indeksu w tablicy – tym razem na miejscu 0 jest product Type – dlatego wszystkie indeksy musisz przesunąć o jeden w górę.

Czyli np. z:

Long id = Long.parseLong(productInformations[0]);

na

Long id = Long.parseLong(productInformations[1]);

ProductSingleton

Skoro pozbyliśmy się już productType w klasie ProductDaoImpl to bez problemu możemy zrobić z tej klasy Singleton.

ProductExceptions

Utwórz cztery wyjątki:

  • ProductCountNegativeException,
  • ProductNameEmptyException,
  • ProductPriceNoPositiveException,
  • ProductWeightNoPositiveException.

Pamiętaj, aby były to wyjątki checked.

ProductValidator

Zbuduj klasę sprawdzająca poprawnośc danych produktu:

  • czy cena jest liczbą większą od zera,
  • czy liczba produktów nie jest ujemna,
  • czy waga jest większa od zera,
  • czy nazwa czasem nie jest pusta.

Pamiętaj o tym, aby dla każdego sprawdzanie utworzyć osobną metodę oraz rzucać wcześniej utworzonego w tym celu wyjątki.

Przebudowa UserValidator

Niestety klasa Uservalidator generowała błędy – UserService zawierał w sobie UserValidator, UserValidator zawierał UserService co ostatecznie powodowało błąd StackOverflowError.

StackOverflowError oznacza, że pamięć maszyny wirtualnej została przepełnione przez ciągłe załączanie obiektów – jeden załączał jeden, a kolejny ten poprzedni i tak w kółko. W taki sposób powstawała pętla nieskończona.

Aby uniknąć tego błędu trzeba wyrzucić z klasy UserValidator pole userService oraz metodę sprawdzającą unikalność loginu czyli isLoginAlreadyExist.

Metodę isLoginAlreadyExist przenieś do UserServiceImpl oraz wywołuj ją przed dodawanie Usera w metodzie addUser.

UserRegisterLoginFacade

Pojawiła się pierwsza fasada w naszej aplikacji – służąca do logowania i rejestracji przez użytkownika.

Jej interfejs wygląda tak:

package api;

import entity.User;

public interface UserRegisterLoginFacade {
    boolean registerUser(User user);
    boolean loginUser(String login, String password);
}

Pamiętaj o tym, aby w klasie UserRegisterLoginFacadeImpl korzystać już tylko z metod z serwisu – w tym przypadku UserRegisterLogin. Nie uzależniaj fasady bezpośrednio od klasy DAO lub walidatorów – za to jest odpowiedzialny wcześniej wspomniany serwis. 😉

Utworzona klasa może być oczywiście Singletonem – jest to porzadane rozwiązanie. 😉

Małe testowanie

W końcu w mainie czas przetestować naszą fasadę oraz serwisy.

W metodzie main stwórz dwie pętle – w jednej będzie działać aplikacja przed zalogowaniem i będzie wyświetlane takie menu:

System.out.println("MANAGEMENT MENU");
System.out.println("1 - Zaloguj się");
System.out.println("2 - Zarejestruj się");
System.out.println("0 - Wyjdź");

Po zalogowaniu się ma wejść w drugą pętle (wewnętrzną) i wyświetlać takie menu:

public static void loggedMenu() {
    System.out.println("MANAGEMENT MENU");
    System.out.println("1 - Dodaj nowy product");
    System.out.println("0 - Wyloguj się");
}

Podczas dodawania produktu ma być wyświetlane takie menu wyboru:

public static void productTypeMenu() {
    System.out.println("1 - Dodaj buty");
    System.out.println("2 - Dodaj ubrania");
    System.out.println("3 - Inne");
}

Kod w mainie będzie wyglądał brzydko – ale to nic. Póki co niech tak zostane, na sam koniec postaramy się dodać interfejs przy użyciu JavyFX – wtedy nie będzie już tyle brzydkiego kodu, ale do tego przeznaczone kontrolery. 😉

Podsumowanie

Na koniec dam Ci skróconą listę zadań do wykonania na ten tydzień:

  1. Przebuduj podane interfejsy i klasy implementujące metody.
  2. Dodaj pole product Type do modeli product.
  3. Zmień działanie ProductParser – ze względu na productType.
  4. Zrób z klay ProductDao singleton.
  5. Stwórz cztery nowe wyjątki dla klasy Product.
  6. Stwórz ProductValidator.
  7. Przebudowa UserValidator
  8. Stwórz fasadę do logowania i rejestracji użytkowników.
  9. Przetestuj rejestrację, logowanie oraz tworzenie produktów w mainie.

Zmian jest naprawdę sporo – w końcu udało się doprowadzić aplikację do porzadanego stanu, gdzie można już dodawać produkty oraz się rejestrować. W następnych tygodniach zajmiemy się nie tylko refaktoryzacją kodu na jeszcze lepsze, ale również usuwaniem produktów.

Oczywiście w razie problemów lub jeśli coś jest nie jasne możesz pisać do mnie maila na maniaq@1024kb.pl, ale najlepiej gdybyś zostawił wiadomość tutaj w komentarzu – więcej osób na tym skorzysta.

Moje przykładowe rozwiązanie możesz podejrzeć tutaj.

 

 

 

 

Kamil Klimek

Od 2016 jestem programistą Java. Przez pierwsze 4 lata pracowałem jako Full Stack Java Developer. Później postanowiłem postawić nacisk na Javę, żeby jeszcze lepiej ją poznać.

Subscribe
Powiadom o
guest
2 komentarzy
najstarszy
najnowszy oceniany
Inline Feedbacks
View all comments
Poul
Poul
5 lat temu

https://github.com/Poul12/myRepository
Nie wiem dlaczego nie musiałeś u siebie łapać wyjątków w Main zapisując product?

Ogólnie, bardzo dobry blog, przejrzysta forma tutoriala i podoba mi się pomysl na projekt, nie mogę sie doczekać na podłączenie do baz danych i podpięcie graficznego interfejsu.

Kamil Klimek
Kamil Klimek
5 lat temu
Reply to  Poul

Cześć, super, że podoba Ci się forma – choć nie jest perfekcyjna i z pewnością zawiera w sobie błędy.

Co do exceptionów to ja je póki co łapę w serwisie, jednak koniecznie będzie trzeba je zrefaktorować i łapać dopiero w fasadzie lub w kontrolerze, który zostanie wkrótce stworzony. 😉

2
0
Would love your thoughts, please comment.x