W jaki sposób mam skonstruować metodę akcesora getTrzymaneKarty(), żeby nie złamać zasady hermetyzacji?
Mam klasę Uzytkownik z polem: private ArrayList<Karta> trzymaneKarty = new ArrayList<Karta>(13);
Mam też oczywiście klasę Karta. Jeśli w klasie Uzytkownik zrobię metodę
public ArrayList<Karta> getTrzymaneKarty() {
return trzymaneKarty;
}
to wystarczy w dowolnej klasie napisać nazwaUzytkownika.getTrzymaneKarty().add(new Karta(3,3));
aby zmienić prywatne pole w klasie Uzytkownik. Pomyślałem, że trzeba zwrócić kopię, ale oczywiście
public ArrayList<Karta> getTrzymaneKarty() {
kopia = trzymaneKarty;
return kopia;
}
taki zapis nic nie da, bo kopia odwoła się do tego samego obiektu i zmieniając kopię jego też zmienimy. Wobec tego pomyślałem, żeby przepisać całą listę do nowej listy i zwrocić tą nową.
ArrayList<Karta> kopia = new ArrayList<Karta>(13);
kopia.addAll(trzymaneKarty);
return kopia;
Jednak nie wiem czemu nagle pojawiać się zaczał błąd przy linii if (temp.get(j).getLiczbaNaKarcie() == temp.get(k).getLiczbaNaKarcie())
"Exception in thread "main" java.lang.IndexOutOfBoundsException: Index: 10, Size: 10
at java.util.ArrayList.rangeCheck(Unknown Source)
at java.util.ArrayList.get(Unknown Source)
at Glowna.wyrzucPary(Glowna.java:85)
at Glowna.main(Glowna.java:22)"
w zasadzie o to też chciałbym zapytać dlaczego przy normalnym 'return trzymaneKarty' błędu nie było, a w tej wersji z kopią się pojawił. Mogę przekopiować cały kod, tylko nie wiem czy to konieczne.
Wracając do głównego problemu. Gdy zacząłem się zastanawiać nad powyższym błędem z kopią, dotarło do mnie, że w ten sposób zwrocę rzeczywiście inną listę i zmiana jej nie zmieni tej prywatnej listy z klasy, ale zwróce w niej te same obiekty klasy Karta co w oryginalnej liście! Wtedy nawet gdyby poprawnie działała wersja z przepisaniem listy do kopii, zabezpieczyłbym się chyba przed
nazwaUzytkownika.getTrzymaneKarty().add(new Karta(3,3));
bo nie dodałoby to już tej karty do trzymanych kart użytkownika. Wystarczy jednak napisać
nazwaUzytkownika.getTrzymaneKarty().get(1).setId(4);
i zmienimy obiekt Karta posiadany przez danego użytkownika w swojej liście trzymaneKarty.
Nie wiem czy zacząłem przesadzać, bo wygląda to dość śmiesznie, kolejno get.get.set na jednym obiekcie. Można zostawiać taką furtkę? Według mnie nie powinno tak być. Jak to rozwiązać, żeby rzeczywiście mieć hermetyczny akcesor? Ewentualnie poproszę o inne rozwiązanie. Widzę, że jest metoda clone(), ale tu sprawa wygląda jak z przepisywaniem listy. Klonuje listę, ale w niej będą referencje do tych samych obiektów klasy Karta. Znalazłem jakieś przykłady z przesłanianiem metody clone(), żeby uzyskać klonowanie głębokie, ale nie do końca się w tym łapie. Do tego w głowie rodzi mi się "a co jeśli Karta też miałaby w sobie referencje do innych obiektów". Przecież potem się w tym nie da połapać.
Kolejna rzecz, którą napotkałem to refleksje. To już dla mnie coś chyba nie do ogarnięcia na ten moment. W głowie już mi się miesza. Doradźcie proszę jak do tego podejść. Napisałbym więcej moich wątpliwości i pomysłów, ale na razie poczekam na odpowiedź, bo nikomu nie będzie się chciało takiego długiego posta czytać.