Zazwyczaj, żeby uchronić wewnętrzne pola danej klasy przed przypadkowymi zmianami,
stosuje się gettery/settery. Getter/setter (nowe polskie słowa ;-) to para publicznych metod pobierających i ustawiających prywatne pola klasy. Oto klasyczny przykład klasy z getterem getValue i setterem setValue.
public class Foo {
private int value = 666;
public void setValue(int newValue) { value = newValue; }
public int getValue() { return value; }
}
...
Foo foo = new Foo();
foo.setValue(100);
System.out.println("Foo value: " + foo.getValue());
...
Powyższe rozwiązanie ma jedną podstawową wadę - trzeba pisać dużo prawie identycznego kodu. Ponieważ jestem osobą leniwą, więc napisałem sobie klasę Property. Nie jest to może odkrycie Ameryki, ale przynajmniej rozwiązuje część problemów natury lenistwa. Poniżej znajduje się zmodyfikowana wersja poprzedniego kodu. Tym razem z wykorzystaniem klasy Property. Od razu widać, że zaoszczędziłem w ten sposób całe dwie linijki kodu. Hurra! Pole value jest zadeklarowane jako public final więc jest dostępne dla innych klas, i zarazem nie możemy zmieniać jego wartości.
public class Foo {
public final Property<Integer> value = new Property<Integer>(666);
}
...
Foo foo = new Foo();
foo.value.set(100); // ok
// foo.value = null; // błąd kompilacji, ponieważ foo.value jest final
System.out.println("Foo value is " + foo.value);
...
Przykład uproszczonej implementacji klasy Property oraz BooleanProperty:
public class Property<T> {
protected T value;
public Property() { this(null); }
public Property(T value) { this.value = value; }
public T get() { return value; }
public void set(T value) { this.value = value; }
public boolean isNull() { return value == null; }
@Override
public String toString() { return (value == null) ? null : value.toString(); }
}
public class BooleanProperty extends Property<Boolean> {
public BooleanProperty() { this(false); }
public BooleanProperty(boolean value) { super(value); }
public void no() { value = false; }
public void set(String value) { super.set(Boolean.parseBoolean(value)); }
public void toggle() { value = !value; }
public void yes() { value = true; }
}
Zauważ, że mając pole typu BooleanProperty, możesz napisać if (foo.value.get()) { ...
Takie rozwiązanie ma również niewielki minusy. Oprócz zmiennej typu Property<T>, w pamięci przechowywane jest również wewnętrzne pole value typu T, więc w niektórych przypadkach zużycie pamięci może wzrosnąć (jednak z drugiej strony oszczędzamy pamięć na metodach get/set, które są wspólne dla wszystkich pól typu Property<T>).
W niektórych przypadkach może nastąpić niewielka utrata przejrzystości kodu (np. addressBook.get().person.get().name.get()) i powstaje kandydat do The Daily WTF ;-)









