Wzorzec projektowy Budowniczy

Wprowadzenie


W świecie programowania i inżynierii często spotykamy się z potrzebą tworzenia złożonych obiektów krok po kroku. Tradycyjne podejścia, takie jak używanie konstruktorów z wieloma parametrami, szybko prowadzą do chaosu i błędów.

Z pomocą przychodzi wzorzec projektowy Budowniczy, który oddziela proces tworzenia obiektu od jego reprezentacji. Dzięki temu ten sam proces budowy może prowadzić do powstania różnych końcowych produktów.

Idea wzorca Budowniczy


Budowniczy należy do grupy wzorców kreacyjnych. Jego głównym celem jest umożliwienie tworzenia złożonych obiektów krok po kroku, w sposób czytelny i elastyczny.

Kluczowe elementy wzorca:

Product (Produkt) – finalny obiekt, który powstaje w wyniku działania budowniczego.

Builder (Budowniczy) – interfejs określający kroki potrzebne do stworzenia produktu,

ConcreteBuilder (Konkretny Budowniczy) – implementacja, która definiuje, jak wykonywane są poszczególne kroki,

Director (Kierownik) – zarządza procesem budowy, wywołując odpowiednie kroki w określonej kolejności,

Designed by Freepik

Przykład z prefabrykacji żelbetowej


Wyobraźmy sobie firmę zajmującą się prefabrykacją elementów żelbetowych (np. słupów, belek czy płyt). Proces wytwarzania takiego elementu wymaga wielu kroków:

  • przygotowanie elementu do transportu.
  • wybór rodzaju betonu,
  • określenie wymiarów,
  • zaprojektowanie zbrojenia,
  • dodanie otworów technologicznych,

Każdy element prefabrykowany może mieć inne parametry, ale proces produkcji przebiega według podobnych etapów.


Budowniczy pozwala stworzyć taki element krok po kroku – najpierw ustalamy beton, potem wymiary, następnie zbrojenie, a na końcu detale. Dzięki temu możemy łatwo tworzyć różne warianty elementów prefabrykowanych, używając tej samej logiki budowy.

Poniżej przykład implementacji wzorca Budowniczy w Javie, który odpowiada na sytuację z prefabrykacją żelbetową:

// Produkt – element prefabrykowany
class PrefabElement {
    private String beton;
    private String wymiary;
    private String zbrojenie;
    private String dodatki;

    private PrefabElement(Builder builder) {
        this.beton = builder.beton;
        this.wymiary = builder.wymiary;
        this.zbrojenie = builder.zbrojenie;
        this.dodatki = builder.dodatki;
    }

    @Override
    public String toString() {
        return "PrefabElement{" +
                "beton='" + beton + '\'' +
                ", wymiary='" + wymiary + '\'' +
                ", zbrojenie='" + zbrojenie + '\'' +
                ", dodatki='" + dodatki + '\'' +
                '}';
    }

    // Budowniczy
    public static class Builder {
        private String beton;
        private String wymiary;
        private String zbrojenie;
        private String dodatki;

        public Builder beton(String beton) {
            this.beton = beton;
            return this;
        }

        public Builder wymiary(String wymiary) {
            this.wymiary = wymiary;
            return this;
        }

        public Builder zbrojenie(String zbrojenie) {
            this.zbrojenie = zbrojenie;
            return this;
        }

        public Builder dodatki(String dodatki) {
            this.dodatki = dodatki;
            return this;
        }

        public PrefabElement build() {
            return new PrefabElement(this);
        }
    }
}

// Użycie wzorca
public class Main {
    public static void main(String[] args) {
        PrefabElement slup = new PrefabElement.Builder()
                .beton("C30/37")
                .wymiary("30x30x300 cm")
                .zbrojenie("4 pręty Ø16, strzemiona Ø8 co 20 cm")
                .dodatki("otwory montażowe")
                .build();

        System.out.println(slup);
    }
}

Zalety tego podejścia


Designed by Freepik

Czytelność – kod budujący obiekt jest intuicyjny i łatwy do zrozumienia,

Elastyczność – możemy łatwo dodawać kolejne opcjonalne kroki budowy,

Unikanie „telescoping constructors” – brak potrzeby definiowania wielu przeciążonych konstruktorów,

Separacja logiki – proces tworzenia oddzielony od reprezentacji produktu,

Łatwe tworzenie różnych wariantów produktu – ten sam proces budowy może prowadzić do różnych reprezentacji.

Wady


Designed by Freepik

Większa liczba klas – wprowadzenie dodatkowego budowniczego i produktu zwiększa złożoność projektu,

Czas implementacji – dla prostych obiektów wzorzec może być nadmiarowy,

Potencjalne obciążenie dla małych projektów – sensowny głównie w dużych aplikacjach lub w systemach złożonych.