Pola czy właściwości?
Pole klasy to zmienna zdefiniowana wewnątrz klasy. Właściwość (ang. property) to wartość, na której operuje jedna lub dwie spośród metod:
Type getXXX()- metoda pobierająca wartość właściwości (ang. getter),
void setXXX(Type value)- metoda ustawiająca wartość właściwości (ang. setter).
Obie metody posiadają ten sam człon XXX – nazwę właściwości. Również typ właściwości (Type) jest w obu przypadkach ten sam.
Poniżej znajduje się przykład pola:
public Integer value;
Właściwość spełniająca tę samą funkcjonalność będzie wyglądać tak:
private Integer value;
public Integer getValue() {
return this.value;
}
public void setValue(Integer value) {
this.value = value;
}
Ale po co w ogóle korzystać z właściwości, skoro zdefiniowanie pola jest dużo szybsze? Co zyskujemy definiując dwie dodatkowe metody?
Po pierwsze można w ten sposób zdefiniować właściwość tylko do odczytu. Wystarczy, że setter nie będzie istniał. Może to być potrzebne w sytuacji, gdy wartość ustawiana jest tylko w konstruktorze albo innych metodach klasy. Analogicznie definiuje się właściwości tylko do zapisu.
Często dostęp do zapisu i odczytu właściwości mają różną widoczność. Na przykład setter chroniony (protected) będzie mógł zostać wywołany poza pakietem jedynie przez klasy potomne. Natomiast domyślna widoczność ograniczy ustawianie wartości jedynie do pakietu, w którym znajduje się klasa.
Ważnym powodem do stosowania właściwości jest potrzeba operowania na wartościach, które nie są przechowywane w polach klasy. Najprostszym przykładem może być hasło:
@Column(name = "password")
private String password;
private String getPassword() {
return decrypt(hexToBytes(this.password));
}
public void setPassword(String password) {
this.password = bytesToHex(encrypt(password));
}
boolean isPassword(String password) {
return this.getPassword().equals(password);
}
W powyższym przykładzie kolumna bazy danych, przechowująca szesnastkowy zapis zaszyfrowanego hasła, mapowana jest na prywatne pole klasy encji. Istnieje jednak właściwość operująca na haśle zapisanym jawnym tekstem – dostępna do odczytu tylko dla składowych klasy. Metody encrypt, decrypt, bytesToHex oraz hexToBytes zdefiniowane są gdzieś wewnątrz klasy.
Podobnie jest z długością okręgu:
private Double radius;
public Double getLength() {
return this.radius * 2.0 * Math.PI;
}
public void setLength(Double length) {
this.radius = length / 2.0 / Math.PI;
}
Pole przechowuje jedynie promień okręgu, natomiast jego obwód obsługiwany jest poprzez właściwość.
Inną sytuacją, wymagającą użycia właściwości, jest powiadamianie obserwatorów o zmianie wartości. Wówczas to właśnie setter jest miejscem, w którym dochodzi do przeprowadzenia tej dodatkowej operacji.
Co prawda w najprostrzych przypadkach można obejść się bez właściwości, lecz warto je stosować nawet wówczas. Pozwoli to w razie potrzeby obejść się bez szerokiego refaktoringu, mającego na celu dostosowanie kodu aplikacji opartego na dostępie do pól do obsługi właściwości.



