Jakie są wspólne , rzeczywiste przykłady świata z użyciem wzoru Builder? Co ci to kupuje? Dlaczego nie użyć tylko wzoru fabrycznego?
java
design-patterns
builder
Charles Graham
źródło
źródło
Odpowiedzi:
Kluczowa różnica między konstruktorem a fabrycznym IMHO polega na tym, że konstruktor jest przydatny, gdy trzeba zrobić wiele rzeczy, aby zbudować obiekt. Na przykład wyobraź sobie DOM. Musisz utworzyć wiele węzłów i atrybutów, aby uzyskać swój ostateczny obiekt. Fabryka jest używana, gdy fabryka może łatwo utworzyć cały obiekt w ramach jednego wywołania metody.
Jednym z przykładów użycia konstruktora jest budowanie dokumentu XML. Użyłem tego modelu podczas budowania fragmentów HTML, na przykład mógłbym mieć Konstruktora do budowania określonego typu tabeli i może mieć następujące metody (parametry nie są pokazane) :
Ten konstruktor wyplułby dla mnie HTML. Jest to o wiele łatwiejsze do odczytania niż przechodzenie przez dużą metodę proceduralną.
Sprawdź Wzór konstruktora na Wikipedii .
źródło
Poniżej znajduje się kilka powodów przemawiających za użyciem wzorca i przykładowego kodu w Javie, ale jest to implementacja Wzorca Konstruktora objętego Gangiem Czterech we Wzorcach Projektu . Powody, dla których chcesz go używać w Javie, dotyczą również innych języków programowania.
Jak stwierdza Joshua Bloch w Effective Java, wydanie drugie :
Wszyscy kiedyś spotkaliśmy klasę z listą konstruktorów, w której każde dodanie dodaje nowy parametr opcji:
Nazywa się to Wzorem Konstruktora Teleskopowego. Problem z tym wzorcem polega na tym, że gdy konstruktory mają długość 4 lub 5 parametrów, trudno jest zapamiętać wymaganą kolejność parametrów, a także konkretny konstruktor, którego możesz chcieć w danej sytuacji.
Jedną z alternatyw dla Telescoping Constructor Pattern jest wzorzec JavaBean, w którym wywołujesz konstruktor z obowiązkowymi parametrami, a następnie wywołujesz dowolne ustawiacze po:
Problem polega na tym, że ponieważ obiekt jest tworzony przez kilka wywołań, może być w niespójnym stanie w trakcie jego budowy. Wymaga to również dodatkowego wysiłku, aby zapewnić bezpieczeństwo nici.
Lepszą alternatywą jest użycie Wzorca konstruktora.
Pamiętaj, że Pizza jest niezmienna, a wszystkie wartości parametrów znajdują się w jednym miejscu . Ponieważ metody ustawiające Buildera zwracają obiekt Builder, można je połączyć w łańcuch .
Powoduje to, że kod jest łatwy do napisania, bardzo łatwy do odczytania i zrozumienia. W tym przykładzie metodę kompilacji można zmodyfikować w celu sprawdzenia parametrów po skopiowaniu ich z konstruktora do obiektu Pizza i wygenerowania wyjątku IllegalStateException, jeśli podano niepoprawną wartość parametru. Ten wzór jest elastyczny i łatwo będzie dodać do niego więcej parametrów w przyszłości. Jest to naprawdę przydatne tylko wtedy, gdy masz więcej niż 4 lub 5 parametrów dla konstruktora. To powiedziawszy, może być opłacalne, jeśli podejrzewasz, że możesz dodać więcej parametrów w przyszłości.
Pożyczyłem dużo na ten temat z książki Effective Java, 2. wydanie Joshua Blocha. Aby dowiedzieć się więcej o tym wzorcu i innych skutecznych praktykach Java , bardzo go polecam.
źródło
new Pizza.Builder(12).cheese().pepperoni().bacon().build();
Pizza.Builder(12).cheese().pepperoni().bacon().build();
musisz ponownie skompilować kod lub mieć niepotrzebną logikę, jeśli potrzebujesz tylko trochę pepperoni pizze. Przynajmniej powinieneś dostarczyć sparametryzowane wersje, takie jak początkowo sugerowany @Kamikaze Mercenary.Pizza.Builder(12).cheese(true).pepperoni(false).bacon(false).build();
. Z drugiej strony, nigdy nie przeprowadzamy testów jednostkowych, prawda?Rozważ restaurację. Stworzenie „dzisiejszego posiłku” jest wzorcem fabrycznym, ponieważ mówisz kuchni „przynieś mi dzisiejszy posiłek”, a kuchnia (fabryka) decyduje o tym, który obiekt wygenerować, na podstawie ukrytych kryteriów.
Kreator pojawi się, jeśli zamówisz niestandardową pizzę. W tym przypadku kelner mówi szefowi kuchni (budowniczy) „Potrzebuję pizzy; dodaj do niej ser, cebulę i bekon!” W ten sposób konstruktor ujawnia atrybuty, które powinien mieć wygenerowany obiekt, ale ukrywa, jak je ustawić.
źródło
Klasa .NET StringBuilder jest doskonałym przykładem wzorca budowniczego. Najczęściej jest używany do tworzenia ciągu znaków w szeregu kroków. Ostateczny wynik uzyskiwania przy wykonywaniu ToString () jest zawsze ciągiem, ale utworzenie tego ciągu zależy od funkcji użytych w klasie StringBuilder. Podsumowując, podstawową ideą jest budowanie złożonych obiektów i ukrywanie szczegółów implementacyjnych dotyczących tego, jak jest budowany.
źródło
b.append(...).append(...)
przed ostatecznym wywołaniemtoString()
. Cytowanie: infoq.com/articles/internal-dsls-javaW przypadku problemu wielowątkowego potrzebowaliśmy zbudować złożony obiekt dla każdego wątku. Obiekt reprezentował przetwarzane dane i może się zmieniać w zależności od danych wejściowych użytkownika.
Czy zamiast tego moglibyśmy skorzystać z fabryki? tak
Dlaczego nie Budowniczy ma chyba więcej sensu.
Fabryki są używane do tworzenia różnych typów obiektów, które są tego samego typu podstawowego (implementują ten sam interfejs lub klasę podstawową).
Konstruktorzy ciągle budują ten sam typ obiektu, ale konstrukcja jest dynamiczna, więc można ją zmieniać w czasie wykonywania.
źródło
Używasz go, gdy masz wiele opcji do czynienia. Pomyśl o takich rzeczach jak jmock:
Wydaje się bardziej naturalny i ... jest możliwy.
Istnieje również budowanie XML, budowanie ciągów i wiele innych rzeczy. Wyobraź sobie,
java.util.Map
że umieścił jako budowniczy. Możesz zrobić takie rzeczy:źródło
Przeglądając środowisko Microsoft MVC, zastanowiłem się nad wzorcem konstruktora. Natknąłem się na wzór w klasie ControllerBuilder. Ta klasa ma zwrócić klasę fabryczną kontrolera, która jest następnie używana do budowy konkretnego kontrolera.
Zaletą, jaką widzę przy użyciu wzorca budowniczego, jest to, że możesz stworzyć własną fabrykę i podłączyć ją do frameworka.
@Tetha, może istnieć restauracja (Framework) prowadzona przez Włocha, która serwuje Pizza. W celu przygotowania pizzy Włoch (Object Builder) używa Owena (Factory) z podstawą do pizzy (klasa podstawowa).
Teraz Indianin przejmuje restaurację od Włocha. Serwery indyjskiej restauracji (Framework) dosa zamiast pizzy. Aby przygotować dosa Indianina (budowniczego obiektów) używa Patelni (fabryka) z Maidą (klasa podstawowa)
Jeśli spojrzysz na scenariusz, jedzenie jest inne, sposób przygotowania jedzenia jest inny, ale w tej samej restauracji (w tych samych ramach). Restauracja powinna być zbudowana w taki sposób, aby obsługiwała kuchnię chińską, meksykańską lub dowolną. Konstruktor obiektów wewnątrz frameworka ułatwia podłączanie żądanej kuchni. na przykład
źródło
Zawsze nie lubiłem wzorca Buildera jako czegoś nieporęcznego, natrętnego i bardzo często wykorzystywanego przez mniej doświadczonych programistów. Jest to wzorzec, który ma sens tylko wtedy, gdy trzeba złożyć obiekt z niektórych danych, co wymaga kroku po inicjalizacji (tj. Po zebraniu wszystkich danych - zrób coś z tym). Zamiast tego w 99% przypadków konstruktory są po prostu używane do inicjowania członków klasy.
W takich przypadkach zdecydowanie lepiej jest po prostu zadeklarować
withXyz(...)
ustawiające typy wewnątrz klasy i sprawić, aby zwróciły odwołanie do siebie.Rozważ to:
Teraz mamy schludną pojedynczą klasę, która zarządza własną inicjalizacją i wykonuje prawie taką samą pracę jak konstruktor, z wyjątkiem tego, że jest znacznie bardziej elegancka.
źródło
Kolejną zaletą konstruktora jest to, że jeśli masz Fabrykę, w twoim kodzie nadal jest trochę sprzężenia, ponieważ aby Fabryka działała, musi znać wszystkie obiekty, które może stworzyć . Jeśli dodasz inny obiekt, który mógłby zostać utworzony, będziesz musiał zmodyfikować klasę fabryczną, aby go uwzględnić. Dzieje się tak również w fabryce abstrakcyjnej.
Z drugiej strony za pomocą konstruktora musisz po prostu stworzyć nowego konstruktora betonu dla tej nowej klasy. Klasa dyrektora pozostanie taka sama, ponieważ otrzymuje konstruktor w konstruktorze.
Ponadto istnieje wiele smaków konstruktora. Kamikaze Mercenary`s daje kolejny.
źródło
źródło
Opierając się na poprzednich odpowiedziach (zamierzone słowa kluczowe), doskonałym przykładem w świecie rzeczywistym jest wbudowane wsparcie Groovy
Builders
.MarkupBuilder
StreamingMarkupBuilder
SwingXBuilder
Zobacz Konstruktorzy w Groovy Documentation
źródło
Użyłem konstruktora w domowej bibliotece wiadomości. Rdzeń biblioteki odbierał dane z drutu, zbierając je za pomocą instancji Builder, a następnie, gdy Builder zdecydował, że ma wszystko, czego potrzeba do utworzenia instancji Message, Builder.GetMessage () konstruował instancję komunikatu na podstawie danych zebranych z drut.
źródło
Sprawdź InnerBuilder, wtyczkę IntelliJ IDEA, która dodaje akcję „Konstruktor” do menu Generuj (Alt + Insert), która generuje wewnętrzną klasę konstruktora, jak opisano w Effective Java
https://github.com/analytically/innerbuilder
źródło
Kiedy chciałem użyć standardowego XMLGregorianCalendar dla mojego XML, aby sprzeciwić się zestawieniu DateTime w Javie, usłyszałem wiele komentarzy na temat jego ciężaru i uciążliwości. Próbowałem kontrolować pola XML w strukturach xs: datetime, aby zarządzać strefą czasową, milisekundami itp.
Zaprojektowałem więc narzędzie do budowy kalendarza XMLGregorian z GregorianCalendar lub java.util.Date.
Ze względu na to, gdzie pracuję, nie mogę udostępniać go online bez legalnego, ale oto przykład, w jaki sposób klient go używa. Wyodrębnia szczegóły i filtruje niektóre implementacje XMLGregorianCalendar, które są rzadziej używane dla xs: datetime.
Przyznaję, że ten wzorzec jest raczej filtrem, ponieważ ustawia pola w xmlCalendar jako niezdefiniowane, więc są one wykluczane, nadal go „buduje”. Z łatwością dodałem inne opcje do konstruktora, aby utworzyć strukturę xs: date i xs: time, a także w razie potrzeby manipulować przesunięciami strefy czasowej.
Jeśli kiedykolwiek widziałeś kod, który tworzy i używa XMLGregorianCalendar, zobaczysz, jak to znacznie ułatwiło manipulowanie.
źródło
Doskonałym przykładem w świecie rzeczywistym jest testowanie lekcji podczas zajęć. Używasz konstruktorów sut (System Under Test).
Przykład:
Klasa:
Test:
sut Builder:
źródło
CustomAuthenticationService
klasy?