Na forum 4programmers.net korzystamy z plików cookies. Część z nich jest niezbędna do funkcjonowania
naszego forum, natomiast wykorzystanie pozostałych zależy od Twojej dobrowolnej zgody, którą możesz
wyrazić poniżej. Klikając „Zaakceptuj Wszystkie” zgadzasz się na wykorzystywanie przez nas plików cookies
analitycznych oraz reklamowych, jeżeli nie chcesz udzielić nam swojej zgody kliknij „Tylko niezbędne”.
Możesz także wyrazić swoją zgodę odrębnie dla plików cookies analitycznych lub reklamowych. W tym celu
ustaw odpowiednio pola wyboru i kliknij „Zaakceptuj Zaznaczone”. Więcej informacji o technologii cookie
znajduje się w naszej polityce prywatności.
Chciałabym, aby ktoś na prostym przykładzie wytłumaczył mi o co chodzi z getterami i setterami w Javie, szukałam w google, na youtubie i w książce, "podstawy javy", swoją drogą dziwne że w książce nawet zdania o tym nie było.
Jedyne informacje jakie znajduje to teorie typu
"Gettery i settery to metody, które pozwalają odpowiednio pobierać i zapisywać wartość pól klasy."
Co nam w praktyce daje stosowanie takich metod ? Jak to zrozumieć ?
Jeśli np. masz klasę "kwadrat" to pewnie nie chcesz żeby jego bok miał ujemną długość, więc jeśli zamiast umożliwienia po prostu modyfikacji zmiennej "bok" zrobisz funkcję "setBok" to w tej funkcji możesz sprawdzać czy długość boku jest sensowna i jeśli nie to np. jakiś wyjątek rzucić.
Metody getter i setter bardziej ogólnie można nazwać mianem akcesorów. Pozwalają one zapewnić enkapsulację danego obiektu. Inaczej ujmując przechowujemy pola w ramach sekcji prywatnej bądź też chronionej natomiast dostęp do tych pól musimy zapewnić poprzez wykorzystanie tych metod getter i setter. Możemy tworzyć dostęp do pól do odczytu z wykorzystaniem metod get, lub/oraz do zapisu z wykorzystaniem metod set. Dzięki temu wyodrębniamy jakiś interfejs dostępu do danych, kolejną zaletę napisał kolega powyżej.
Poza tym, niektóre wartości obiektu mogą być np. automatycznie wyliczane na podstawie innych pol, wtedy raczej nie będziesz chciała udostępnić settera dla takiego pola.
Przykład:
Klasa kwadrat, będziesz chciała miec możliwość ustawienia długości pola a i b, jednak zamiast wprowadzić manualnie wartość pola tego kwadratu, raczej zadbasz o to, aby getPole() automatycznie je wyliczyło na podstawie podanych boków.
Czasem tez dany obiekt nie może istnieć bez jakiejś wartości, np Użytkownik bez loginu.
W takiej sytuacji powinnaś udostępnić konstruktor, w którym użytkownik będzie musiał podać login, sama metoda setLogin() może wtedy być pominięta.
A w takim typowo prostym programie gdzie wczytuję, wyświetlam imię i nazwisko:
Kopiuj
publicclass firstHello {staticScanner wczytywarka =newScanner(System.in);publicstaticvoidmain(String[] args){System.out.println("Podaj swoje imie: ");String imie =pobierzDane();System.out.println("Twoje imie to: "+ imie);System.out.println("Podaj swoje nazwisko: ");String nazwisko =pobierzDane();System.out.println("Twoje nazwisko to: "+ nazwisko);}publicstaticStringpobierzDane(){return wczytywarka.nextLine();}}
Można na siłę użyć getterów i setterów ? Jakby to wyglądało ?
Moim zdaniem do takiego zadania nie jest to potrzebne, ale czytałam że trzeba od samego początku uczyć się tego używać nawet w miejscach które mogą się obyć bez tego.
@wioletta90 gettery i settery są związane z klasami/strukturami a twój program ma słowo class tylko dlatego że java wymaga żeby main() było w jakiejś klasie.
Wyobraź sobie że masz klasę
Kopiuj
class Osoba{
private final String imie;
private final String nazwisko;
}
i to do takiego obiektu chcesz wczytać dane a potem je wypisać...
Ano usuwanie tego finala to zły pomysł. Obiekty mutowalne są bardzo niewygodne i należy się ich wystrzegać jak ognia. Najwygodniej pracuje się z obiektami które nie mogą sie już zmienić po utworzeniu. Oczywiscie wtedy trzeba by zrobić jakieś
Kopiuj
new Osoba(wczytajDane(), wczytajDane());
Poza tym ta "wczytywarka" powinna być zmienną w funkcji main() a nie statycznym polem klasy. W ogóle klasa z main() raczej nie powinna mieć żadnych pól.
Rozumiem, że obiekty mutowalne to takie które się zmieniają, ale
Kopiuj
privatefinalString imie;
to pole a nie obiekt ?
Takie rzeczy jak imię, nazwisko w programach raczej będę się zmieniały, a
Kopiuj
final
chyba to zablokuje i będzie jedno stałe imię/nazwisko ?
Tego nie rozumiem od poczatku do końca:
Oczywiscie wtedy trzeba by zrobić jakieś
Kopiuj
newOsoba(wczytajDane(),wczytajDane());
Gdy usunęłam static i przeniosłam
Kopiuj
Scanner wczytywarka =newScanner(System.in);
do metody main() z klasy, to w metodzie pobierzDane() podkreśliło mi "wczytywarka" i wyświetliło bład "wczytywarka cannot be resolved", jak sobie z tym poradzić ?
W ogóle klasa z main() raczej nie powinna mieć żadnych pól.
Chodzi o metodę main() ? Jeżeli nie, to co to jest klasa z main() ? Tak jak mówi nazwa? Klasa w której jest metoda(main) ? W sumie jeszcze nie widziałam programu z dwiema klasami.
@wioletta90 obiekty mutowalne to takie które mogą zmieniać swój stan, a stan obiektu zwykle określają jego pola właśnie. Nie odróżniasz OBIEKTU od KLASY. Klasą jest np. Krzesło a obiektem może być krzesło na którym teraz siedzisz i krzesła które masz w kuchni. Widzisz różnicę? Polem klasy może być materiał z którego wykonane jest krzesło, a każde z twoich krzeseł może być wykonane z innego materiału. Ten materiał zapewne jest "niezmienny" tzn drewniane krzesło nagle nie stanie sie metalowe. Więc jak widzisz niezmienność/niemutowalność nijak nie sprawia że nie możesz mieć różnych krzeseł. Tak samo jest z Osobami. Osoba raczej nie zmieni nagle swojego imienia i nazwiska ;]
Ten scanner musisz sobie teraz do tej metody przekazać jako parametr. Dużo łatwiej analizuje się kod kiedy metody/funkcje dostają w parametrach obiekty z którymi mają pracować.
Nie, nie chodzi mi o metodę main. Chodzi mi o klasę w której masz main(). Ta klasa powinna zawierać tylko tego maina i nic więcej.
Ale kombinujecie. @wioletta90 pyta o tak podstawowe rzeczy jak akcesory, dopiero zaczyna się uczyć OOP a @Shalom z mutowalnością wyskakuje.
@wioletta90 jak najbardziej usuń final i korzystaj z akcesorów żeby zmieniać wartości obiektu. Na bardziej skomplikowane zagadnienia przyjdzie jeszcze czas. Ważne żebyś zrozumiała sens używania akcesorów.
a to Zelent źle uczy ? Nie jestem w temacie a oglądałam trochę.
Shalom
To przestań oglądać bo więcej z tego będzie krzywdy niż pożytku.
Aventus
@Shalom Mutowalność ma swoje zalety i wady tak samo jak i niemutowalność. Co za tym idzie nie są one ani dobre ani złe, wszystko zależy od kontekstu w jakich się ich używa. Twierdząc że niemutowalność jest jedyną słuszną drogą- to jest dopiero "doskonały plan".
Shalom
Chętnie poczytam o tych rzekomych zaletach mutowalności, szczególnie w kontekście dużych, prawdziwych aplikacji z wielowątkowością i wielodostępem.
Gettery i settery generalnie są uważane za nieładne przy obiektach domenowych bo łamią enkapsulacje, niemniej czasem trudno ich uniknąć. Wyobraź sobie że masz teraz listę List<Osoba> w programie i chcesz wybrać z tej listy tylko osoby z nazwiskiem na jakaś literkę, albo o danym imieniu. Jak zrobisz to bez gettera? ;)
a więc usunęłam settery i przekazałam odpowiednie parametry do metody pobierzDane(), teraz nie wiem jak bez setterów pobrać dane od użytkownika, wcześniej miałam
osobnik.setImie(pobierzDane());
, czyli wywoływałam metode dla obiektu osobnik z parametrem pobierzDane() [pokazuje jak myślę, jak źle to dajcie znać]
proponuję zrobić wczytywanie dla imienia taką linijką kodu:
Kopiuj
String imie = wczytywarka.nextLine();
to co aktualnie mam:
Kopiuj
packagepl.wioletta.hello;importjava.util.Scanner;publicclassOsoba{privatefinalString imie;privatefinalString nazwisko;publicStringgetImie(){return imie;}publicStringgetNazwisko(){return nazwisko;}publicclassKlasaZMain{publicstaticvoidmain(String[] args){Scanner wczytywarka =newScanner(System.in);Osoba osobnik =newOsoba();System.out.println("Podaj swoje imie: ");System.out.println("Podaj swoje nazwisko: ");}}publicstaticStringpobierzDane(Scanner wczytywarka){return wczytywarka.nextLine();}}
Settery na DTO sugerują że możesz przypadkiem trafić na obiekty które nie są do końca zainicjalizowane albo są niespójne. (a piewcy DDD w ogóle powiedzą że DTO to zło ;) )
zdaję sobie z tego sprawę, w moich własnych projektach mam normalnie prywatne. podałem to po prostu jako ciekawostkę, że ktoś coś tak dziwnego wymyślił i to funkcjonuje
karolinaa
pytanie do @Pythonowcow - jak sobie radzicie bez getterów i setterów. oraz czy dodatkowa logika w getterach i setterach to jest okey? generalnie wiem, że jest okey w normalnych projektach jak to w życiu bywa, ale gdybyśmy znajdowali sie w idealnym świecie ideii. to czy settery i gettery to są mądre i dodatkowa logika w nich jest ok? @szarotka dała dobrą myśl
Shalom
Na przykład "logika" walidująca poprawność danych, albo aktualizująca jakieś inne pola obiektu, albo w ogóle "getter" który coś wylicza i zwraca, bo potem z takiego DTO automatem generujemy sobie JSONa i chcemy tam mieć jakąś wartość która niekoniecznie jest polem obiektu. Python ma property -> http://www.python-course.eu/python3_properties.php
dao (model) -> service (pluje immutable DTOsami) -> JSFowy controller widoku
to teraz w tym controlerze pobieram sobie z serwisu np. List<AccountDto> accountList i tak to mogłabym trzymać tą listę w polu w klasie kontrolera jako private List<AccountDto>
i np w takim datatable się iterować i mieć na wierszu np. input texta z value="#{acc.name}" itd... AccountDto ma settery i na końcu wołam jedynie service.update(accountList).
a tak to jak AccountDto jest immutable i nie mam setterow to co wtedy? muszę zrobić specjalnie kolejną klasę tym razem muttable opakowującą AccountDto dla jsfowego kontrolera?
interesuje mnie ten konretny przypadek z datatable.
Nie mówię, że ta dodatkowa klasa to źle tylko pytam z niewiedzy i zastanawiam się na jakim etapie złamanie tych zasad ma sens i przy jakiej skali wielkości projektu
przestrzeganie tych wszystkich zasad daje więcej czasu i fajności niż zabiera.
Mam nadzieje że to co nazwałaś "controller widoku" i w którym to chcesz mieć pola, to jest Managed Bean, bo inaczej to jest jakiś WTF.
To jest oczywiście szczególny przypadek kiedy robisz input beana do którego chcesz wpakować dane z Widoku, bo wtedy technologia może na tobie wymusić posiadanie bezparametrowego kontruktora i setterów (zgodnie z konwencja JavaBeans). I o ile tylko tam w sposób niejawny te settery są użyte to ok.
Analogiczny problem może występować np. dla klas @Entity ale to jest zupełnie inna bajka kiedy mówimy o czymś co wymusza na tobie użyta technologia.
@wioletta90 no i ekstra, ja bym tylko utworzyła zmienne imię i nazwisko i przekazała do konstruktora te zmienne zamiast wczytajDane() - kwestia czytelności kodu
czyli niby teraz do konstruktora mam przekazać jako parametr 2 takie same metod wczytajDane(), ale po co ? Chciałam,aby program wczytał imię po linijce
System.out.println("Podaj swoje imie: ");String imie =wczytajDane(scanner);System.out.println("Podaj swoje nazwisko: ");String nazwisko =wczytajDane(scanner);Osoba osoba =newOsoba(imie, nazwisko);
Zaraz muszę gdzieś poszukać chyba ten link z pracą jako pomocnik piekarza...
OK, nie śledziłam całego wątku, ale właściwie czemu nie zrobisz:
Kopiuj
publicstaticvoidmain(String[] args){Scanner wczytywarka =newScanner(System.in);System.out.println("Podaj swoje imie: ");String imie =wczytajDane(scanner);System.out.println("Podaj swoje nazwisko: ");String nazwisko =wczytajDane(scanner);//teraz masz juz imię i nazwisko, więc tworzysz obiektOsoba osobnik =newOsoba(imie, nazwisko);}
Wydaje mi się, że zbytnio kombinujesz. Nie programuj na ślepo permutacjami tylko poczytaj solidnie o podstawach i pomyśl jak to wykombinować i prawidłowo zrobić.
Nie tak byle działało tylko pomyśl tak jak komputer. Popatrz czemu nie zrobisz w taki sposób:
Kopiuj
System.out.println("Podaj swoje imie: ");finalString imie =wczytajDane(scanner);System.out.println("Podaj swoje nazwisko: ");finalString nazwisko =wczytajDane(scanner);finalOsoba obiektOsoba =newOsoba(imie, nazwisko);
oczywiście wbij to do bloku public static void main(String[] args) { ;]
ShalomAventusShalom