Chcę powiadomić programistę, gdy próbuje zmutować niezmienny obiekt. Obiekt niezmienny jest w rzeczywistości rozszerzeniem zmiennego obiektu i przesłonił seterów na wymienionym obiekcie, aby stał się niezmienny.Czy powinienem rzucić wyjątek w próbie mutacji niezmiennej klasy? Jeśli tak, jaki wyjątek?
Zmienna klasa bazowa: Vector3
public class Vector3 {
public static final Vector3 Zero = new ImmutableVector3(0, 0, 0);
private float x;
private float y;
private float z;
public Vector3(float x, float y, float z) {
this.x = x;
this.y = y;
this.z = z;
}
public void set(float x, float y, float z) {
this.x = x;
this.y = y;
this.z = z;
}
}
wersja Niezmienne: ImmutableVector3
public final class ImmutableVector3 extends Vector3 {
public ImmutableVector3(float x, float y, float z) {
super(x, y, z);
}
//Made immutable by overriding any set functionality.
@Override
public void set(float x, float y, float z) {
throw new Exception("Immutable object."); //Should I even throw an exception?
}
}
Moje przypadek użycia jest następujący:
public class MyObject {
//position is set to a flyweight instance of a zero filled vector.
//Since this is shared and static, I don't want it mutable.
private Vector3 position = Vector3.Zero;
}
Powiedzmy, że develo na mój zespół decyduje, że potrzebuje manipulować pozycją obiektu, ale obecnie jest ustawiony na statyczną, niezmienną instancję wektora współdzielonego Vector3.Zero.
Byłoby najlepiej, gdyby wiedział z wyprzedzeniem, że musi utworzyć nową instancję zmienny wektor jeżeli wektor pozycja jest ustawiona na udostępnionym instancji Vector3.Zero:
if (position == Vector3.Zero)
position = new Vector3(x, y, z);
Ale załóżmy, że najpierw tego nie sprawdza. Myślę, że w tym przypadku dobrze byłoby rzucić wyjątek, jak pokazano powyżej w metodzie ImmutableVector3.set(x,y,z)
. Chciałem użyć standardowego wyjątku Java, ale nie byłem pewien, który byłby najbardziej odpowiedni i nie jestem w 100% przekonany, że jest to najlepszy sposób, aby sobie z tym poradzić.
Sugestie, które widziałem (to pytanie) [Czy nielegalny stan wyjątku jest właściwy dla obiektu niezmiennego? zdają się sugerować następujące:
- IllegalStateException - ale to jest niezmienne obiekt, co ma tylko jednego państwa
- UnsupportedOperationException - metoda
set()
jest obsługiwana, ponieważ zastępuje klasę bazową, więc może to być dobry wybór . - Wyjątek NoSuchElementException - nie jestem pewien, w jaki sposób byłby to dobry wybór, chyba że metoda jest uważana za
element
.
Co więcej, nie jestem nawet pewien, czy powinienem tu podać wyjątek. Nie mogłem po prostu zmienić obiektu i nie powiadomić programisty, że próbują zmienić niezmienny obiekt, ale wydaje się to również kłopotliwe. Problem z wyrzuceniem wyjątku w ImmutableVector3.set(x,y,z)
polega na tym, że set
musi wyrzucić wyjątek zarówno dla ImmutableVector3
jak i Vector3
. Więc teraz, nawet jeśli Vector3.set(x,y,z)
nigdy nie wyrzuci wyjątku, musi zostać umieszczony w bloku try/catch
.
- jestem widokiem innej opcji oprócz rzucania wyjątków?
- Jeśli wyjątki są najlepszym rozwiązaniem, który wyjątek powinienem wybrać?
Pozwoliłbym użyć 'UnsuppoertedOperationException'. Dekoratory 'niemodyfikowalne *' z 'Collection' są dobrym precedensem. – kiheru
@crush Czy rozwiązujesz * znany * problem z wydajnością, modyfikując Vector3D? Jeśli nie, po prostu unieważnij. Niech ludzie konstruują nową instancję, gdy chcą nowych wartości. Znany problem z wydajnością = wykonałeś testowanie/analizę wydajności i to było wąskie gardło. –
@EricStein wartości Vector3 będą się zmieniać co sekundę lub częściej dla setek tysięcy obiektów w moim zasięgu. Jestem pod, prawdopodobnie fałszywym założeniem, że tworzenie nowego obiektu Vector3 za każdym razem, gdy potrzebuję zmienić położenie obiektu, może ostatecznie spowodować problemy z GC pauzami i/lub być wolniejsze niż po prostu ustawienie nowej pozycji na istniejącym obiekcie. – crush