Widzę najbardziej niezmienne POJO napisane w ten sposób:
public class MyObject {
private final String foo;
private final int bar;
public MyObject(String foo, int bar) {
this.foo = foo;
this.bar = bar;
}
public String getFoo() {
return foo;
}
public int getBar() {
return bar;
}
}
Mimo to mam tendencję do pisania ich w ten sposób:
public class MyObject {
public final String foo;
public final int bar;
public MyObject(String foo, int bar) {
this.foo = foo;
this.bar = bar;
}
}
Zauważ, że odniesienia są ostateczne, więc Obiekt jest nadal niezmienny. Pozwala mi pisać mniej kodu i umożliwia krótszy (o 5 znaków: dostęp geti ()).
Jedyną wadą, jaką widzę, jest to, że jeśli chcesz zmienić implementację w getFoo()dół drogi, aby zrobić coś szalonego, nie możesz. Ale realistycznie to się nie zdarza, ponieważ Obiekt jest niezmienny; możesz zweryfikować podczas tworzenia instancji, tworzyć niezmienne kopie obronne podczas tworzenia instancji (patrz ImmutableListna przykład Guava ) i przygotować obiekty foolub barobiekty na getwezwanie.
Czy brakuje mi wad?
EDYTOWAĆ
Przypuszczam, że kolejną wadą, której mi brakuje, są biblioteki serializacji wykorzystujące refleksję nad metodami zaczynającymi się od getlub is, ale to dość okropna praktyka ...
String, intlub MyObject. W pierwszej wersji finalma jedynie zapewnić, że metody inne niż konstruktor w klasie nie będą próbować bar = 7;na przykład. W drugiej wersji, finaljest konieczne, aby zapobiec konsumentów robi: MyObject x = new MyObject("hi", 5); x.bar = 7;.
Objectnadal są niezmienne. ” Są mylące - w ten sposób wydaje się, że uważasz, że każdy final Objectjest niezmienny, a tak nie jest. Przepraszam za nieporozumienie.
myObj.getFoo().setFrob(...).
finalnie czyni zmiennej niezmienną. Zwykle używam projektu, w którym definiujęfinalpola przed utworzeniem wywołania zwrotnego, aby wywołanie zwrotne mogło uzyskać dostęp do tych pól. Może oczywiście wywoływać wszystkie metody, w tym dowolnesetX.