Zaloguj się
Projekty Kategorie Archiwum

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 ;-)

Proszę o komentarz

zenon
Środa 31 sierpnia, 2005 00:02

Łał, mówisz o Javie jakby była czymś superłatwym... Z jakiej książki najlepiej zacząć naukę żeby przynajmniej zrozumieć o czym piszesz :)?

Środa 31 sierpnia, 2005 00:40

Jakoś nie rozumiem idei getterów i setterów skoro sprowadzają się do value = dupa i return value.

Środa 31 sierpnia, 2005 00:47

<flame>

Ech, toż to nawet JavaScript ma normalne gettery i settery:

function Foo(value) {
var _value = parseInt(value);

this.__defineGetter__("value", function() {
return _value;
});

this.__defineSetter__("value", function(newVal) {
_value = parseInt(newVal);
});

}

aFoo = new Foo(8);
alert(aFoo.value);

aFoo.value="2005r.";
alert(aFoo.value);

bFoo = new Foo(9);
alert(bFoo.value);

bFoo.value="50 procent Polaków nie wie, że stanowi połowę społeczeństwa";
alert(bFoo.value);

...a w Javie trzeba cudować. ;-)

</flame>

Środa 31 sierpnia, 2005 01:08

@zenon: Ja akurat nie uczyłem się z książek :) Wg mnie najlepiej wyznaczyć sobie jakiś z pozoru nieosiągalny cel (np. napisanie menedżera plików), a potem stopniowo tworzyć program krok-po-kroku (najpierw okno, tytuł okna, lista z plikami, itd.) Oczywiście jakieś dobre podstawy by się przydały. W archiwum grup dyskusyjnych temat książek był poruszany miliardy razy ;)

@zdzichu: ?ettery często wykonują bardziej złożone operacje niż tylko proste przypisanie. Poza tym zmniejsza się ryzyko, że przypadkowo przypiszesz do value jakąś przypadkową wartość.

@marcoos: Fajne, ale chyba parseInt ucina tekst za liczbą ;)

Środa 31 sierpnia, 2005 01:10

Jak zmniejszaja ryzyko? Czym się różni foo.value = 0xbad od foo.setValue(0xbad) ?

Środa 31 sierpnia, 2005 01:17

@zdzichu:
1. Po 12 godzinach pisania foo.value=0xdeadbeef można pomylić z value=0xdeadbeef (lub odwrotnie).
2. Funkcja foo.setValue(0xdeadbeef) może wywołać wyjątek, jeśli wartość jest nieprawidłowa.
3. ?ettery są też używane przez JavaBeans (akurat nie znam się na tym)

Środa 31 sierpnia, 2005 01:22

Jam: parseInt() jest tam tylko po to, żeby w skutkach się to wyraźnie różniło od foo.value = newValue (kiedy value nie jest setterem/getterem).

steelheart
Środa 31 sierpnia, 2005 01:30

a jak takie podejscie sie sprawuje gdy sie z refleksji kozysta ?
jak na to by zareagowal taki kontener serwletow czy inszy hibernate ?

Środa 31 sierpnia, 2005 19:51

Założę się, że ktoś już napisał odpowiednie adnotacje do generowania ?etterów.

Środa 31 sierpnia, 2005 21:05

@Jezuch: generowanie na podst. adnotacji a zwykła klasa, to dwa różne podejścia

nbmb
Czwartek 13 października, 2005 22:17

mbnmcbn

Środa 3 czerwca, 2009 20:07

?ettery są bardzo przydatne. Dzięki nim np. na pierwszy rzut oka widać, co wolno zrobić z daną klasą, a czego nie wolno. Otwieranie dostępu „pól klasy” (cytuję, nie znam javy) zwiększa co prawda „uniwersalność” takiej klasy, bo można z zewnątrz w te pola wpisać co nam się rzewnie podoba, ale klasa(instancja) nie ma wtedy kontroli nad poprawnością tych danych. Generalnie przy większym projekcie robi się wtedy chaos, chaos powstaje zawsze, gdy nie ma z góry określonych metod postępowania, a IMVHO ?ettery działają narzucają takie reguły :-)

Zdzichu
Środa 13 kwietnia, 2011 13:42

Ale ze mnie PA-TA-FIAN.

Napisz komentarz

Dodaj komentarz

Formatowanie komentarza

Kategorie

Ewolucja Internetu 8 | Fail 40 | Gry 46 | Humor 129 | Idiotyzm 50 | Java 110 | KDE 85 | KShutDown 22 | Linux 84 | Makagiga 58 Muzeum 3 | Ogólne 819 | Polityka 76 | Programowanie 51 | Reklamy 4 | Techblog 19 | Teorie Spiskowe 12 | TV 59 | UI 9 | Użyteczność 30 | WWW 90 | Wyrwane z Kontekstu 34 | X Files 14

Archiwum

Maj 2012 | Kwiecień 2012 | Marzec 2012 | Luty 2012 | Styczeń 2012 | Grudzień 2011 | Listopad 2011 | Październik 2011 | Wrzesień 2011 | Sierpień 2011 | Lipiec 2011 | Czerwiec 2011 | Maj 2011 | Kwiecień 2011 | Styczeń 2011 | Listopad 2010 | Październik 2010 | Wrzesień 2010 | Sierpień 2010 | Lipiec 2010 | Czerwiec 2010 | Kwiecień 2010 | Marzec 2010 | Luty 2010 | Styczeń 2010 | Grudzień 2009 | Listopad 2009 | Październik 2009 | Wrzesień 2009 | Sierpień 2009 | Lipiec 2009 | Czerwiec 2009 | Maj 2009 | Kwiecień 2009 | Marzec 2009 | Styczeń 2009 | Grudzień 2008 | Listopad 2008 | Październik 2008 | Wrzesień 2008 | Sierpień 2008 | Lipiec 2008 | Czerwiec 2008 | Maj 2008 | Kwiecień 2008 | Marzec 2008 | Luty 2008 | Styczeń 2008 | Grudzień 2007 | Listopad 2007 | Październik 2007 | Wrzesień 2007 | Sierpień 2007 | Lipiec 2007 | Czerwiec 2007 | Maj 2007 | Kwiecień 2007 | Marzec 2007 | Luty 2007 | Styczeń 2007 | Grudzień 2006 | Listopad 2006 | Październik 2006 | Wrzesień 2006 | Sierpień 2006 | Lipiec 2006 | Czerwiec 2006 | Maj 2006 | Kwiecień 2006 | Marzec 2006 | Luty 2006 | Styczeń 2006 | Grudzień 2005 | Listopad 2005 | Październik 2005 | Wrzesień 2005 | Sierpień 2005 | Lipiec 2005 | Czerwiec 2005 | Maj 2005 | Kwiecień 2005 | Marzec 2005 | Luty 2005 | Styczeń 2005