Zastosowanie
Budowniczy
(ang. Builder
) (wzorzec kreacyjny) rozdziela sposób tworzenia obiektów od ich reprezentacji. Dzieli proces wytwórczy obiektu na etapy. Każdy z etapów może być zaimplementowany na wiele sposobów co umożliwia tworzenie różnych reprezentacji obiektów tej samej klasy. Dzięki zastosowaniu podejścia odwrócenia zależności
zmiana sposobu tworzenia obiektów jest elastyczna i odbywa się niskim kosztem. Ponadto kod jest łatwiejszy w testowaniu, utrzymaniu, zapewnieniu obsługi wyjątków oraz zapobiega duplikacji. Wzorzec ten działa na podobnej zasadzie co plan budowy. Dyrektor
odpowiedzialny za całą budowę zleca wykonanie poszczególnej pracy konkretnym Budowniczym
. W efekcie połączenia ich pracy powstaje finalny Produkt
. Mówiąc o wzorcu Budowniczy
nie sposób nie wspomnieć o jego odmianie tzw. Fluent Builder
. Jego rola sprowadza się do tworzenia obiektów (z dużą ilością parametrów) w czytelny sposób poprzez zastępienie konstruktora.
Ograniczenia
Stosowanie wzorca wymusza tworzenie konkretnego Budowniczego
dla każdego typu Produktu
co zwiększa ilość klas. Ponadto nie ma gwarancji inicjalizacji pól klasy, a Wstrzykiwanie Zależności
może być utrudnione.
Użycie
Budowniczy
używany jest w implementacji złożonych obiektów (kompozytów
), które mogą być budowane na różne sposoby, a ich inicjalizacja jest procesem wieloetapowym. Zastosowanie wzorca pozwala uniknąć tworzenia super klasy o rozbudowanej odpowiedzialności. Wykorzystywany jest w inicjalizacji kompozytów
w wielu bibliotekach zewnętrznych oraz także systemowych. W sytuacjach, gdy konstruktor klas ma długą listę parametrów (ok 5) należy rozważyć zastosowanie Fluent Builder
.
Implementacja
W klasycznej wersji wzorca obiekt klasy Director
zleca wykonanie produktu (Product
) konkretnemu builderowi (ConcreteBuilder
) nadzorując jego pracę. Director
przechowuje referencje do Buildera
i w momencie budowania produktu wywołuje na nim poszczególne operacje. Każdy budowniczy implementuje wspólne zachowania abstrakcyjnej klasy Builder
lub interfejsu, tworząc produkt na swój określony sposób. Builder
zawiera referencję do produktu i zwraca go nadzorcy w momencie zakończenia pracy.
Poniższy listing przedstawia implementacje klasycznej postaci wzorca Budowniczy
.
Klient korzystając z nadzorcy wykorzystuje zaimplementowany wzorzec w następujący sposób.
W wersji Fluent Builder
, instancja klasy Product
tworzona jest poprzez wywołanie statycznej klasy Builder
. Stosując ten sposób tworzenia obiektów, należy zadbać o inicjalizacje wszystkich wymaganych pól oraz jej kolejność. Poniższy listing pokazuje podstawową implementacje wzorca w wariancie Fluent Builder
.
Dzięki takiemu zabiegowi zamiast tworzyć obiekt poprzez wywołanie jego konstruktora można posłużyć się jego budowniczym.
Przykład
Aplikacja wspomaga pracowników sieci gastronomicznej w przyjmowaniu i wydawaniu zamówień. Pracownik obsługi Staff
wybiera na ekranie wskazane przez klienta zdefiniowane zestawy obiadowe Meal
. Sztab kucharzy Cook
w którym każdy specjalizuje się w konkretnym daniu otrzymuje listę zamówień do realizacji. Po przygotowaniu posiłku przekazuje go do obsługi, a stamtąd trafia ono do klienta. Poniższy listing przedstawia sposób realizacji składania zamówień przy użyciu Budowniczego
.
Dodatkowo klient może skomponować swój własny zestaw. W tym celu pracownik obsługi ręcznie wybiera produkty. Poniższy listing przedstawia implementację manualnego tworzenia zestawu przy użyciu Fluent Builder
.
Proces wyboru zestawów wygląda następująco.
Biblioteki
Wiele bibliotek zewnętrznych jak np.: Retrofit
czy elementów systemu np.: AlertDialog
, Notification
korzysta z Budowniczego
. Jednakże do samej implementacji wzorca przeważnie nie używa się bibliotek. Metoda append
klas StringBuilder
oraz StringBuffer
mogą być przykładem realizacji wzorca Budowniczy
w Javie
.