Создание сложных объектов может быть громоздким и трудным в управлении, особенно когда задействовано несколько конфигураций и комбинаций компонентов. Шаблон Builder — это шаблон проектирования, который упрощает процесс создания сложных объектов, позволяя создавать их шаг за шагом. Это приводит к более читабельному, поддерживаемому и гибкому коду.

В этом посте мы углубимся в паттерн Builder и продемонстрируем его практическое применение на примере, реализованном в Go. Мы создадим объект Product из нескольких частей, демонстрируя способность шаблона Builder облегчить создание сложных объектов, сохраняя при этом гибкость для легкого создания различных конфигураций.

Перейти к реализации шаблона Builder

На протяжении всего поста мы представим реализацию шаблона Builder на Go и объясним ключевые задействованные компоненты, такие как Product, Builder и ConcreteBuilder. Мы также обсудим их соответствующие роли в процессе строительства. Приведенный пример иллюстрирует, как шаблон Builder можно использовать для пошагового создания сложных объектов, что позволяет легко настраивать различные варианты объектов.

Устранение утечки конфигурации между сборками

В этом посте мы также рассмотрим распространенную ловушку в реализациях шаблонов Builder, а именно потенциальную утечку конфигураций между разными сборками. Мы продемонстрируем, как правильно сбрасывать внутреннее состояние компоновщика после каждой сборки, чтобы убедиться, что конфигурации изолированы и не влияют на последующие сборки.

package main

import "fmt"

// Product represents the complex object to be built.
type Product struct {
 partA string
 partB string
 partC string
}

func (p *Product) String() string {
 return fmt.Sprintf("Product{partA: %s, partB: %s, partC: %s}", p.partA, p.partB, p.partC)
}

// Builder is the interface for building a complex object step by step.
type Builder interface {
 SetPartA(string) Builder
 SetPartB(string) Builder
 SetPartC(string) Builder
 Build() *Product
}

// ConcreteBuilder is the concrete implementation of the Builder interface.
type ConcreteBuilder struct {
 product Product
}

func (cb *ConcreteBuilder) SetPartA(value string) Builder {
 cb.product.partA = value
 return cb
}

func (cb *ConcreteBuilder) SetPartB(value string) Builder {
 cb.product.partB = value
 return cb
}

func (cb *ConcreteBuilder) SetPartC(value string) Builder {
 cb.product.partC = value
 return cb
}

func (cb *ConcreteBuilder) Build() *Product {
 product := cb.product
 cb.reset()
 return &product
}

// reset resets the builder's internal product state.
func (cb *ConcreteBuilder) reset() {
 cb.product = Product{}
}

func main() {
 builder := &ConcreteBuilder{}

 // Building a product using the builder
 product1 := builder.SetPartA("Custom part A").SetPartB("Custom part B").SetPartC("Custom part C").Build()
 fmt.Println("Product 1:", product1)

 // Building another product with different configuration
 product2 := builder.SetPartA("Another part A").SetPartB("Another part B").Build()
 fmt.Println("Product 2:", product2)
}

В этом примере у нас есть три основных компонента:

  1. Product: Строящийся сложный объект. В данном случае он состоит из трех частей (partA, partB и partC).
  2. Builder: Интерфейс для пошагового построения сложного объекта. В нем есть методы настройки каждой части (SetPartA, SetPartB и SetPartC) и метод построения конечного продукта (Build).
  3. ConcreteBuilder: конкретная реализация интерфейса Builder. Он реализует каждый метод установки деталей и метод сборки конечного продукта. Метод internalreset сбрасывает внутреннее состояние продукта компоновщика на новый пустой объект Product. Мы вызываем метод reset внутри метода Build перед возвратом сконструированного продукта. Это гарантирует, что конфигурация одного продукта не повлияет на конфигурацию следующего продукта, созданного с использованием того же компоновщика.

В функции main мы создаем ConcreteBuilder, строим Product с помощью компоновщика и печатаем полученный продукт. В этом примере показано, как шаблон Builder можно использовать для пошагового создания сложных объектов, что позволяет использовать различные конфигурации и более читаемый и удобный код.

Заключение

Поняв шаблон Builder и его реализацию на Go, вы будете хорошо подготовлены для применения шаблона в своих собственных проектах, тем самым упрощая процессы создания сложных объектов и повышая удобочитаемость и удобство сопровождения вашего кода.

Если вам нравится читать статьи на Medium и вы заинтересованы в том, чтобы стать участником, я буду рад поделиться с вами своей реферальной ссылкой!

https://medium.com/@adamszpilewicz/membership