Proste. private, final, settery be, blablablabblssadasdknsfoiwdf. Jeśli potrzebujesz odświeżyć definicję, to wejdź tu albo gdziekolwiek chcesz, wszędzie to samo będzie napisane.

J. Bloch napisał w Effective Java:

“Classes should be immutable unless there’s a very good reason to make them mutable.”

Też fajnie, można zapamiętać, ale nadal nie wiemy po co to wszystko, mimo że już znamy definicję.

Obiekty stanowe

We wpisie o enkapsulacji wspomnieliśmy o stanowości obiektu. W dokumentacji Oracle’a przeczytasz o obiektach tak:

They all have state and behavior. Dogs have state (name, color, breed, hungry) and behavior (barking, fetching, wagging tail).

Znowu ten biedny pies. Przykład na piesku rozwiązuje wszystkie problemy kuli ziemskiej. Weźmy za przykład klasę Account. Niech to będzie Twoje konto na Netflixie. Niech ma trzy stany. Active, Inactive, Blocked, które operują na polach klasy Account. Ustawienie każdego z tych stanów zależy od jakichś czynników np.:

Active – konto jest aktywne, gdy jest opłacone

Inactive – konto staje się nieaktywne, gdy go nie opłacisz lub gdy nie jest używane przez 1 rok, cokolwiek

Blocked – konto jest zablokowane, gdy złamiesz regulamin serwisu lub gdy okazało się, że dzielisz się swoim kontem z całym osiedlem

Reguły nie są tu super istotne. Grunt, że są i zarówno stanów jak i reguł może być znacznie więcej. O ile stosujemy poprawnie enkapsulację to nasz obiekt może przybrać trzy różne stany. Jeśli nie stosujemy enkapsulacji to możemy wprowadzić obiekt w jakiś niepożądany, niezdefiniowany biznesowo stan. Prosty przykład tu.

Mamy więc trzy znane stany obiektu. Tworzy to już jakąś tam złożoność. Na pewno obiekt z trzema stanami będzie bardziej złożony (choćby w zakresie liczby linii) od tego co ma dwa stany lub jeden stan.

Jeden stan. Najfajniej. Jeden stan i brak możliwości zmiany tego stanu na żaden inny po utworzeniu obiektu. Mmmmmmmm. Taki obiekt jest prosty. Prosty w użyciu, prosty w zrozumieniu, prosty w czytaniu. Jest on immutable.

Ok. Ale kiedy robić obiekty immutable i jak mogę popsuć sobie życie. gdy obiekt powinien być niemutowalny, a ja go takim nie zrobiłem.

Nieoczekiwana zmiana stanu obiektu

Przypomnijmy sobie pewien fakt o klasie java.util.Date. Musimy pamiętać, że klasa ta nie jest immutable. Do czego to może prowadzić. Poniższy przykład wziąłem stąd. Fajnie trafia do wyobraźni.

Skoro klasa java.util.Date jest mutowalna, a z definicji wynika, że możemy zmienić jej stan, to rezultatem powyższego fragmentu może być nieopatrzne popsucie kodziku. Zamysłem nieostrożnego programisty było pewnie ustawienie nowej daty wykonania dla taska task2 (linia nr 3). Jednak mutowalność klasy Date doprowadziła do tego, że teraz oba taski zostaną wywołane o tej samej porze. Referencja o nazwie d wskazuje na pewien obiekt w pamięci i poprzez użycie settera zmieniliśmy stan tego obiektu.

Nieco dłuższy przykład, ale równie prosty pokazujący to samo zagrożenie umieściłem na GitHubie. Znajdują się tam dwa kodziki prezentujące jedną historyjkę w dwóch wersjach. Pierwsza wersja jest zaimplementowana przy pomocy klasy mutowalnej (pakiet mutable), a druga przy pomocy klasy niemutowalnej (pakiet immutable). Komentarze w klasie App (main()) wszystko Ci rozjaśnią, na pewno się połapiesz, a jak nie to pisz.

Polecam też przykład pod tym linkiem. Kliknij link, kliknij CTRL+F i wklej: Risky example #2: returning mutable values, to skoczysz od razu do owego przykładu.

Dużym benefitem wynikającym z użycia klas immutable jest też to, że nie trzeba synchronizować ich kodu między wątkami. Ale nie jest to chyba niespodzianka, skoro wiemy, że klasy immutable mają jeden stan i nie da się go zmienić. Więc wątki mogą nam skoczyć. Nadają się też perfekt na klucz w mapie. Na każdej stronie poświęconej klasom immutable wyczytasz wszystkie zalety, gdybyś potrzebował np.: ułożyć je sobie w głowie przed rozmową. Moim celem było zebranie trzech przykładów, które dadzą więcej niż kilka zdań 🙂

Tu możesz przeczytać co J. Gosling mówi o klasach immutable.

Leave a Reply

Your email address will not be published. Required fields are marked *