Sobes.tech
Middle

Opowiedz o wzorcu projektowym 'Budowniczy'.

sobes.tech AI

Odpowiedź od AI

Wzorzec projektowy "Builder" (Budowniczy) jest wzorcem kreacyjnym, który umożliwia tworzenie złożonych obiektów krok po kroku. Oddziela proces konstruowania złożonego obiektu od jego reprezentacji, tak aby ten sam proces budowania mógł tworzyć różne reprezentacje.

Główne komponenty:

  • Budowniczy (Builder): Interfejs lub klasa abstrakcyjna definiująca metody tworzenia części złożonego obiektu.
  • Konkretna Budowa (Concrete Builder): Implementuje interfejs Budowniczego i zapewnia konkretną realizację tworzenia części obiektu. Przechowuje wynik pośredni i udostępnia metodę do uzyskania gotowego obiektu.
  • Reżyser (Director): Opcjonalny komponent. Określa kolejność wywołań metod budowniczego do tworzenia obiektu. Nie zna konkretnych budowniczych.
  • Produkt (Product): Złożony obiekt tworzony przez budowniczego.

Zastosowania:

  • Gdy proces tworzenia obiektu jest skomplikowany i obejmuje wiele opcjonalnych kroków.
  • Gdy konieczne jest tworzenie różnych reprezentacji tego samego obiektu, korzystając z tego samego procesu budowania.
  • Gdy konstruktor obiektu ma dużą liczbę parametrów.

Przykład w Go:

// Produkt - złożony obiekt
type Product struct {
	PartA string
	PartB string
	PartC string
}

// Builder - interfejs budowniczego
type Builder interface {
	BuildPartA()
	BuildPartB()
	BuildPartC()
	GetProduct() *Product
}

// ConcreteBuilder - konkretny budowniczy
type ConcreteBuilder struct {
	product *Product
}

func NewConcreteBuilder() *ConcreteBuilder {
	return &ConcreteBuilder{product: &Product{}}
}

func (cb *ConcreteBuilder) BuildPartA() {
	cb.product.PartA = "Część A zbudowana"
}

func (cb *ConcreteBuilder) BuildPartB() {
	cb.product.PartB = "Część B zbudowana"
}

func (cb *ConcreteBuilder) BuildPartC() {
	cb.product.PartC = "Część C zbudowana"
}

func (cb *ConcreteBuilder) GetProduct() *Product {
	return cb.product
}

// Reżyser - opcjonalny
type Director struct {
	builder Builder
}

func NewDirector(builder Builder) *Director {
	return &Director{builder: builder}
}

func (d *Director) Construct() {
	d.builder.BuildPartA()
	d.builder.BuildPartB()
	d.builder.BuildPartC()
}

// Użycie
// concreteBuilder := NewConcreteBuilder()
// director := NewDirector(concreteBuilder)
// director.Construct()
// product := concreteBuilder.GetProduct()
// fmt.Printf("Utworzony produkt: %+v\n", product)

Zalety:

  • Izoluje kod tworzenia obiektu od kodu klienta.
  • Pozwala na zmianę wewnętrznej reprezentacji produktu bez modyfikacji kodu klienta.
  • Pozwala na krokowe budowanie obiektu.
  • Ułatwia tworzenie obiektów z dużą liczbą parametrów.

Wady:

  • Zwiększa ilość kodu (klas/interfejsów) potrzebnego do tworzenia obiektu.
  • Może być nadmiarowe dla prostych obiektów.