Niedawno zacząłem czytać Efektywną Javę Joshuy Blocha. Pomysł wzorca Builder [punkt 2 w książce] wydał mi się bardzo interesujący. Próbowałem zaimplementować to w swoim projekcie, ale wystąpiły błędy kompilacji. Oto w istocie to, co próbowałem zrobić:
Klasa z wieloma atrybutami i jej klasa konstruktora:
public class NutritionalFacts {
private int sodium;
private int fat;
private int carbo;
public class Builder {
private int sodium;
private int fat;
private int carbo;
public Builder(int s) {
this.sodium = s;
}
public Builder fat(int f) {
this.fat = f;
return this;
}
public Builder carbo(int c) {
this.carbo = c;
return this;
}
public NutritionalFacts build() {
return new NutritionalFacts(this);
}
}
private NutritionalFacts(Builder b) {
this.sodium = b.sodium;
this.fat = b.fat;
this.carbo = b.carbo;
}
}
Klasa, w której staram się użyć powyższej klasy:
public class Main {
public static void main(String args[]) {
NutritionalFacts n =
new NutritionalFacts.Builder(10).carbo(23).fat(1).build();
}
}
Otrzymuję następujący błąd kompilatora:
otaczająca instancja, która zawiera efektywne fakty.BuilderPattern.NutritionalFacts.Builder jest wymagana NutritionalFacts n = new NutritionalFacts.Builder (10) .carbo (23) .fat (1) .build ();
Nie rozumiem, co oznacza ta wiadomość. Proszę wytłumacz. Powyższy kod jest podobny do przykładu zasugerowanego przez Blocha w swojej książce.
java
design-patterns
builder-pattern
Swaranga Sarma
źródło
źródło
Odpowiedzi:
Uczyń budowniczego
static
klasą. Wtedy zadziała. Jeśli nie jest statyczny, wymagałby instancji klasy będącej jej właścicielem - a chodzi o to, aby nie mieć jej instancji, a nawet zabronić tworzenia instancji bez konstruktora.Odniesienie: klasy zagnieżdżone
źródło
Builder
jeststatic
to przykład w książce (str. 14, wiersz 10 w 2. wydaniu).Powinieneś ustawić klasę Builder jako statyczną, a także powinieneś sprawić, by pola były ostateczne i mieć metody pobierające, aby uzyskać te wartości. Nie podawaj ustawiania tych wartości. W ten sposób Twoja klasa będzie niezmienna.
Teraz możesz ustawić właściwości w następujący sposób:
źródło
final
pola mają sens tylko wtedy, gdy są one zawsze potrzebne podczas inicjalizacji. Jeśli nie, to pola nie powinny byćfinal
.Próbujesz uzyskać dostęp do klasy niestatycznej w sposób statyczny. Zmień
Builder
nastatic class Builder
i powinno działać.Przykładowe użycie, które podajesz, zawodzi, ponieważ nie ma żadnego wystąpienia
Builder
. Klasa statyczna do wszystkich celów praktycznych jest zawsze tworzona. Jeśli nie zrobisz tego statycznym, musisz powiedzieć:Ponieważ za
Builder
każdym razem musiałbyś konstruować nowy .źródło
Aby wygenerować wewnętrzny kreator w Intellij IDEA, sprawdź tę wtyczkę: https://github.com/analytically/innerbuilder
źródło
Musisz zadeklarować
Builder
klasę wewnętrzną jakostatic
.Zapoznaj się z dokumentacją dotyczącą zarówno niestatycznych klas wewnętrznych, jak i statycznych klas wewnętrznych .
Zasadniczo niestatyczne instancje klas wewnętrznych nie mogą istnieć bez dołączonej instancji klasy zewnętrznej.
źródło
Kiedy już wpadniesz na pomysł, w praktyce może się okazać, że lombok będzie o
@Builder
wiele wygodniejszy.@Builder
umożliwia automatyczne tworzenie kodu wymaganego do tworzenia instancji Twojej klasy za pomocą kodu, takiego jak:Oficjalna dokumentacja: https://www.projectlombok.org/features/Builder
źródło
Oznacza to, że nie możesz utworzyć typu zamkniętego. Oznacza to, że najpierw musisz utworzyć instancję klasy „nadrzędnej”, a następnie z tej instancji możesz utworzyć instancje klas zagnieżdżonych.
Klasy zagnieżdżone
źródło
Klasa Builder powinna być statyczna. Nie mam teraz czasu, aby faktycznie przetestować kod poza tym, ale jeśli to nie zadziała, daj mi znać, a przyjrzę się jeszcze raz.
źródło
Osobiście wolę zastosować inne podejście, gdy masz 2 różne klasy. Więc nie potrzebujesz żadnej statycznej klasy. Zasadniczo ma to na celu uniknięcie pisania,
Class.Builder
gdy musisz utworzyć nową instancję.Możesz więc użyć swojego kreatora w następujący sposób:
źródło
Jak wielu już tutaj powiedziało, musisz stworzyć klasę
static
. Tylko mały dodatek - jeśli chcesz, jest trochę inny sposób bez statycznego.Rozważ to. Implementowanie konstruktora przez zadeklarowanie czegoś podobnego do
withProperty(value)
ustawiaczy typów wewnątrz klasy i sprawienie, aby zwracały odwołanie do siebie. W tym podejściu masz pojedynczą i elegancką klasę, która jest bezpiecznym i zwięzłym wątkiem.Rozważ to:
Sprawdź to, aby uzyskać więcej przykładów Java Builder .
źródło
Musisz zmienić klasę Builder na statyczną klasę Builder . Wtedy będzie działać dobrze.
źródło