Klasy – ciąg dalszy
W poprzedniej lekcji nauczyłeś się tworzyć klasy – deklarować i inicjalizować w nich pola oraz używać konstruktorów: bezparametrowego i parametrowego.
Możliwe, że już zauważyłeś, że konstruktor parametrowy zazwyczaj jest przydatniejszy. Dzięki niemu możemy wprowadzić ustalone wartości do obiektu podczas jego tworzenia – no i mamy wtedy gotową paczuchę z naszymi wartościami. 😉
Sprawę pól w klasie mamy obcykane – czas na pisanie i używanie metod w klasie.
Ze względu, że takie klasy jak User są nazywane modelami lub entity – ich zadaniem jest po prostu przechowywanie informacji. W takim razie stworzymy sobię drugą klasę.
UserService – tak własnie nazywa się klasa, którą sobie stworzymy. Jak nazwa mówi będzie to jakiś serwis userowy – czyli będzie on wykonywał pewne operację na obiektach typu User.
Zazwyczaj w programowaniu trzyma się pewnych konwencji nazewniczych: serwisy własnie mają sufiks Service, walidatory Validator itd. – aby móc w prostych sposób rozróżnić odpowiedzialność klas.
Po co nam ten serwis…
Serwis będzie przechowywał w sobie metody odpowiedzialne za operację na Userze – spójrz, że kolejny raz grupujemy wspólne zagadnienia w jedną klasę!
Czy nie można byłoby tego zrobić w klasie User?
Nikt Ci tego nie zabroni – lecz jest to bardzo brzydkie zachowanie i nie wolno tak robić!
Single Responsibility Principle
Jednym z punktów dobrych praktyk jest właśnie Single Responsibility Principle – czyli ZASADA JEDNEJ ODPOWIEDZIALNOŚCI.
Podkreślam JEDNEJ!
Dlatego nasze klasy powinny być oddzielona – każda powinna być odpowiedzialna za określony cel.
Klasa User jest odpowiedzialna za przechowywanie informacji o Userze.
Klasa UserService będzie odpowiedzialna za przeróżne operację na Userze.
Skoro wiesz po co ten cały cyrk to możemy przejść do tworzenia naszej klasy. 😉
User
Do operowania na obiektach User w UserService oczywiście potrzebujemy klasy User.
Klasa User jest taka sama jak ta, którą stworzyliśmy w poprzedniej lekcji.
public class User { String login; String password; String email; int age; public User() { login = "login"; password = "pass"; email = "mail@example.com"; age = 0; } public User(String login, String password, String email, int age) { this.login = login; this.password = password; this.email = email; this.age = age; } }
Mając klasę User możemy przejść dalej. 😉
UserService
Wystartujemy oczywiście z pustej klasy – którą potrafisz już tworzyc.
public class UserService { }
Zazwyczaj serwisy nie są zbyt bogate w pola – mógłaby ona zawierać tylko jedno pole z obiektem odpowiedzialnym za kontakt z bazą danych.
Ze względu, że u nas nie mamy bazy danych to stwórzmy po prostu tablicę dla czterech userów – przypuśćmy, że to jest nasza baza danych. 😉
User [] users = new User[4]
Stworzymy tylko konstruktor bezparametrowy – a w nim zainicjalizujemy czterech userów, aby mieć na czym pracować – choć w realnym projekcie to nie powinno tak wyglądać. Robimy to tylko w celach edukacyjnych. 😉
public UserService() { users[0] = new User("admin", "pass", "mail", 32); users[1] = new User("user", "pass", "mail", 62); users[2] = new User("pablo", "pass", "mail", 52); users[3] = new User("esco", "pass", "mail", 21); }
Skoro mamy już przygotowany podstawowy szablon naszej klasy to czas stworzyć jakieś metody – my stworzymy dwie.
getUserByLogin
Już wiesz jakie zadanie będzie miała ta metoda?
Jeżeli nie to posłuchaj – będzie ona miała za zadanie wyszukać usera po podanych loginie.
Powinna zapalić się lampka w głowie – getUser – czyli musi zwracać User.
Kolejnym punktem jest kolejny człon metody – ByLogin – czyli po loginie – czyli musimy go podać przez argument do funkcji. 😉
No i mamy taką sygnaturę funckcji:
public User getUserByLogin(String login) { }
Czas na ciało funkcji – musimy przeszukać całą tablicę (naszą małą bazę danych 😉 ), aby znaleźć usera o podanym loginie.
Wykorzystamy do tego pętle – najłatwiej będzie wykorzystać foreach.
for (User user:users) { }
Dzięki niej przejdziemy po wszystkich userach tablicy, potrzebny nam teraz warunek, który będzie zwracał prawdę, gdy loginy będą równe. 😉
boolean isSameLogin = user.login.equals(login);
Chwilę się zatrzymamy -login wyciągane usera zawiera się w: user.login – jest to login usera z tablicy.
Na tym loginie – na obiekcie typu String – wywołujemy wbudowaną metodę equals – która działa bardzo podobnie jak operator == – choć działa lepiej. O czym można poczytać w tym artykule.
Metoda equals przyjmuje jako argument drugi obiekt typu String – i metoda equals zwraca prawdę jeżeli podany argument jest równy obiektowi, na którym wywoływana jest metoda equals.
Jeżeli, więc loginy są równe to możemy zwrócić znalezionego Usera z metody.
if (isSameLogin) { return user; }
Używając w pętli instrukcji return – automatycznie przerwiemy działanie metody i zwrócimy – wyplujemy – znalezionego usera.
Jednak co jeśli nie znajdziemy?
Jednym ze sposobów jest zwrócenie null.
return null;
Czym jest null?
Null jest tak naprawdę niczym – nie wskazuje na żaden obszar w pamięci. Null może być zwrócony za każdym razem, gdy oczekujemy jakiegoś obiektu.
Czyli nie możemy zwrócić w takiej metodzie:
public int getInt() { return null; }
Taka metoda nie zadziała, ponieważ int nie jest obiektem – tylko typem prymitywnem.
Za to zwracając Stringa:
public String getString() { return null; }
To można już zastosować taki myk – ponieważ String jest obiektem.
W Javie jest prosta zasada – typy pisane z małej litery są typami prymitywnymi np. int, char, short itd. – typy obiektowe są pisane z dużej litery.
Skoro wiemy czym jest null to podsumujmy jak wygląda nasza metoda:
public User getUserByLogin(String login) { for (User user:users) { boolean isSameLogin = user.login.equals(login); if (isSameLogin) { return user; } } return null; }
Użyjmy jej teraz w main!
Testowanie UserService.getUserByLogin
Stwórzmy na początku obiekt typu UserService w main:
public class Main { public static void main(String[] args) { UserService userService = new UserService(); } }
Wykorzystajmy teraz naszą metodę do znalezienia usera o loginie: pablo.
User user = userService.getUserByLogin("pablo");
Wynik – czyli Usera lub null przypisujemy do obiektu user.
Wypiszmy na ekran co się znalazła nasza metoda.
System.out.println("Znaleziono usera: " + user.login + " " + user.email);
Po uruchomieniu:
Znaleziono usera: pablo mail
Czyli nasza metoda działa wyśmienicie.
Sprawdźmy jej działanie, gdy nie znajdzie użytkownika:
User kamil = userService.getUserByLogin("kamil");
Oraz wypiszmy tak samo na ekran konsoli:
Exception in thread "main" java.lang.NullPointerException at pl.maniaq.Main.main(Main.java:12) Znaleziono usera: pablo mail
Błąd w 12 linii – co tam jest?
System.out.println("Znaleziono usera: " + kamil.login + " " + kamil.email);
Czyli chodzi pewnie o obiekt kamil.
Został wyrzucony błąd: NullPointerException – znowu ten null.
User nie został znaleziony, więc zostały zwrócony null – czyli nic! Nie jest on żadnym obiektem – nie możemy, więc na nim wywołać login i email!
Zróbmy zabezpieczenie przy użyciu if.
if (kamil != null) { System.out.println("Znaleziono usera: " + kamil.login + " " + kamil.email); } else { System.out.println("Nie znaleziono usera."); }
Mamy zabezpieczenie – jeżeli nasz obiekt kamil nie jest nullem – to dopiero wtedy wyświetlamy informację. W przeciwnym razie nie używamy go – bo go nie ma!
Znaleziono usera: pablo mail Nie znaleziono usera.
No i teraz wszystko działa poprawnie. 😉
sumUsersAge()
Stwórzmy jeszcze jedną metodę: liczącą sumę wieku wszystkich użytkowników.
public int sumUsersAge() { }
Aby przejść po wszystkich użytkownikach potrzebujemy pętli – a do sumowania wieku zmiennej. 😉
int sumAge = 0; for (User user:users) { }
No i w pętli sumujemy – na koniec zwracamy sumę. I tak wygląda nasza cała metoda:
public int sumUsersAge() { int sumAge = 0; for (User user:users) { sumAge += user.age; } return sumAge; }
Przetestujmy jej działanie:
int sumAge = userService.sumUsersAge(); System.out.println("Suma wieku wszystkich użytkowników to: " + sumAge);
Po uruchomieniu:
Suma wieku wszystkich użytkowników to: 167
No i wszystko ponownie działa poprawnie. 😉
Podsumowanie
Po pierwsze lekcji powinieneś już potrafić tworzyć proste klasy – z polami i konstruktorem. Po tej lekcji powinieneś potrafić tworzyć w tych klasach metody oraz potrafić je wywoływać. Sprawdź się wykonując poniższe zadania. 😉
- Stwórz klasę NumberService – będzie ona odpowiedzialna za operację na liczbach, które będą zapisane w polu klasy w tablicy – tak samo jak w lekcji Userzy. Tablica wygląda tak: int [] numbers = {10, 2, 3, 85, 23, 491, 23, 412, 42, 41, 22, 25}; Napisz następujące metody w klasie:
-
- getCountNumbers() – zwracająca liczbę liczb
- countNumbersHigherThan(int number) – zwraca ilość liczb większy od podanej jako argument
- countNumbersLowerThan(int number) – zwraca ilość liczb mniejszych od podanej jako argument
- sumNumbers() – zwraca sumę liczb
- sortNumbers() – sortuje liczby
- displayNumbers() – wyświetla wszystkie liczby
-
- Stwórz klasę Human – w której będziesz przechowywał imię, wzrost i wagę człowieka – inicjalizowane przez konstruktor parametrowy.
- Stwórz klasę HumanService – która będzie w sobie zawierała tablicę 5 obiektów typu Human ( z zadania drugiego). Na tablicy tych obiektów wykonuj operację przy użyciu metod. Stwórz te metody:
- countHumanTallerThan(int height) – zwraca ilość ludzi mających większy wzrost niż podany jako argument
- countHumanLowerThan(int height) – zwraca ilość ludzi mających mniejszy wzrost niż podany jako argument
- countWeights() – zwraca łączną wagę wszystkich ludzi
- countHeights() – zwraca łączny wzrost wszystkich ludzi
- getCountHumans() – zwraca liczbę ludzi na liście
- getHumanByName(String name) – zwraca usera, który ma tak samo na imię jak imię podane jako argument
Wszystkie metody przetestuje w klasie Main – a do sortowania liczb możesz wykorzystać sortowanie bąbelkowe – najprostsze sortowanie. 😉
Rozwiązania zadań możesz znaleźć tutaj.
Jeżeli udało Ci się rozwiązać wszystkie zadania to czas przejść do następnej lekcji. 😉
Świetny materiał! Przerobiłem go właśnie i muszę Ci pogratulować sposobu w jaki prezentujesz wiedzę :)! Wcześniej uczyłem się z książki i poradników na youtube, jednak nigdy nie zrozumiałem klas w takim stopniu jak po tej lekcji :)! Wszystko wydaje się jasne, proste, i intuicyjne :). Zadania przerobione bez większych problemów!
Pozdrawiam :)!
Super, że forma do Ciebie trafia. 😉 Staram się jak najbardziej po ludzku tłumaczyć programowanie, posługując się czasami prostymi obrazkami. 😉