Middle
Czym jest wzorzec projektowy 'Builder'?
sobes.tech AI
Odpowiedź od AI
Wzorzec projektowy "Builder" (Budowniczy) jest wzorcem kreacyjnym, który zapewnia sposób tworzenia złożonego obiektu krok po kroku. Oddziela proces konstruowania złożonego obiektu od jego reprezentacji, co pozwala na użycie tego samego procesu konstruowania do tworzenia różnych reprezentacji.
Kluczowe komponenty wzorca:
- Builder: Abstrytny lub konkretny interfejs (lub klasa), definiujący zestaw metod do krokowego budowania części produktu.
- ConcreteBuilder: Konkretna implementacja Buildera, która tworzy specyficzną reprezentację produktu. Zna wszystkie szczegóły budowy.
- Director: Opcjonalna, ale często używana klasa. Określa kolejność wywołań kroków budowy, aby utworzyć określoną konfigurację produktu.
- Product: Złożony obiekt, który jest budowany. Składa się z wielu części.
Zalety:
- Pozwala na krokowe tworzenie złożonych obiektów, unikając konstruktorów "teleskopowych" (z wieloma parametrami).
- Enkapsuluje logikę tworzenia złożonego obiektu.
- Ułatwia zmianę wewnętrznej reprezentacji produktu.
- Pozwala na użycie tego samego procesu konstruowania do tworzenia różnych wariantów produktu.
Zastosowania:
- Gdy proces tworzenia obiektu obejmuje wiele kroków i te kroki muszą być wykonywane w określonym porządku.
- Gdy konieczne jest posiadanie różnych reprezentacji tego samego obiektu.
- Gdy konstruktor obiektu ma wiele opcjonalnych parametrów.
Przykład:
// Produkt
class Pizza {
private String dough = "";
private String sauce = "";
private List<String> toppings = new ArrayList<>();
public void setDough(String dough) {
this.dough = dough;
}
public void setSauce(String sauce) {
this.sauce = sauce;
}
public void addTopping(String topping) {
this.toppings.add(topping);
}
@Override
public String toString() {
return "Pizza z ciastem: " + dough + ", sosem: " + sauce + ", dodatkami: " + toppings;
}
}
// Interfejs budowniczego
interface PizzaBuilder {
void buildDough();
void buildSauce();
void buildToppings();
Pizza getPizza();
}
// Konkretna implementacja
class MargheritaPizzaBuilder implements PizzaBuilder {
private Pizza pizza = new Pizza();
@Override
public void buildDough() {
pizza.setDough("cienkie ciasto");
}
@Override
public void buildSauce() {
pizza.setSauce("pomidorowa");
}
@Override
public void buildToppings() {
pizza.addTopping("mozzarella");
pizza.addTopping("bazylia");
}
@Override
public Pizza getPizza() {
return this.pizza;
}
}
// Reżyser (opcjonalny)
class Cook {
private PizzaBuilder pizzaBuilder;
public void setPizzaBuilder(PizzaBuilder pb) {
pizzaBuilder = pb;
}
public Pizza getPizza() {
return pizzaBuilder.getPizza();
}
public void constructPizza() {
pizzaBuilder.buildDough();
pizzaBuilder.buildSauce();
pizzaBuilder.buildToppings();
}
}
// Użycie
public class BuilderExample {
public static void main(String[] args) {
Cook cook = new Cook();
PizzaBuilder margheritaBuilder = new MargheritaPizzaBuilder();
cook.setPizzaBuilder(margheritaBuilder);
cook.constructPizza();
Pizza margherita = cook.getPizza();
System.out.println(margherita);
}
}
W kontekście automatyzacji testów, "Builder" jest często używany do tworzenia danych testowych lub złożonych obiektów testowych (np. obiektu użytkownika z wieloma atrybutami, zamówienia z wieloma pozycjami), gdy konieczne jest elastyczne konfigurowanie różnych wariantów tych danych dla różnych scenariuszy testowych.