Struktury mają swoje miejsce, nawet w Javie. Powinieneś ich używać tylko wtedy, gdy są spełnione następujące dwie rzeczy:
- Musisz tylko agregować dane, które nie mają żadnego zachowania, np. Przekazać jako parametr
- Nie ma znaczenia, jakie wartości mają agregowane dane
W takim przypadku należy upublicznić pola i pominąć metody pobierające / ustawiające. Gettery i settery i tak są niezgrabne, a Java jest głupia, ponieważ nie ma właściwości takich jak przydatny język. Ponieważ obiekt podobny do struktury i tak nie powinien mieć żadnych metod, pola publiczne są najbardziej sensowne.
Jeśli jednak jedno z nich nie ma zastosowania, masz do czynienia z prawdziwą klasą. Oznacza to, że wszystkie pola powinny być prywatne. (Jeśli absolutnie potrzebujesz pola w bardziej dostępnym zakresie, użyj gettera / settera.)
Aby sprawdzić, czy domniemana struktura ma zachowanie, sprawdź, kiedy pola są używane. Jeśli wydaje się to naruszać powiedz, nie pytaj , musisz przenieść to zachowanie na swoją klasę.
Jeśli niektóre Twoje dane nie powinny ulec zmianie, musisz uczynić wszystkie te pola ostatecznymi. Możesz rozważyć uczynienie swojej klasy niezmienną . Jeśli potrzebujesz zweryfikować swoje dane, podaj weryfikację w ustawiaczach i konstruktorach. (Przydatną sztuczką jest zdefiniowanie prywatnego setera i zmodyfikowanie pola w klasie za pomocą tylko tego setera).
Twój przykład butelki prawdopodobnie nie przejdzie obu testów. Możesz mieć (wymyślony) kod, który wygląda następująco:
public double calculateVolumeAsCylinder(Bottle bottle) {
return bottle.height * (bottle.diameter / 2.0) * Math.PI);
}
Zamiast tego powinno być
double volume = bottle.calculateVolumeAsCylinder();
Gdybyś zmienił wysokość i średnicę, czy byłaby to ta sama butelka? Prawdopodobnie nie. Te powinny być ostateczne. Czy wartość ujemna jest odpowiednia dla średnicy? Czy Twoja butelka musi być wyższa niż szeroka? Czy czapka może być zerowa? Nie? Jak to sprawdzasz? Załóżmy, że klient jest głupi lub zły. ( Nie można odróżnić. ) Musisz sprawdzić te wartości.
Tak może wyglądać Twoja nowa klasa Bottle:
public class Bottle {
private final int height, diameter;
private Cap capType;
public Bottle(final int height, final int diameter, final Cap capType) {
if (diameter < 1) throw new IllegalArgumentException("diameter must be positive");
if (height < diameter) throw new IllegalArgumentException("bottle must be taller than its diameter");
setCapType(capType);
this.height = height;
this.diameter = diameter;
}
public double getVolumeAsCylinder() {
return height * (diameter / 2.0) * Math.PI;
}
public void setCapType(final Cap capType) {
if (capType == null) throw new NullPointerException("capType cannot be null");
this.capType = capType;
}
// potentially more methods...
}