Создание сложных объектов с множеством необязательных параметров может оказаться непростой задачей.

Традиционный подход конструктора и установщика может стать громоздким при работе с объектами со многими необязательными параметрами.

В этой статье мы рассмотрим шаблон построителя, порождающий шаблон проектирования, который позволяет создавать сложные объекты с множеством необязательных параметров.

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

+----------------+               +-------------------+
|     Director   |  directs      |      Builder      |
+----------------+               +-------------------+
| construct()    | ------------> | buildPart1()      |
| setBuilder()   |               | buildPart2()      |
+----------------+               | getProduct()      |
                                 +-------------------+
                                           |
                                           V
                                 +-------------------+
                                 |      Product      |
                                 +-------------------+
                                 | field1            |
                                 | field2            |
                                 | ...               |
                                 +-------------------+

Реализация шаблона Builder в Go

Вот пример шаблона построителя в golang

type Car struct {
 Make       string
 Model      string
 Year       int
 Color      string
 EngineSize float64
}

type CarBuilder struct {
 Car
}

func (cb *CarBuilder) SetMake(make string) *CarBuilder {
 cb.Make = make
 return cb
}

func (cb *CarBuilder) SetModel(model string) *CarBuilder {
 cb.Model = model
 return cb
}

func (cb *CarBuilder) SetYear(year int) *CarBuilder {
 cb.Year = year
 return cb
}

func (cb *CarBuilder) SetColor(color string) *CarBuilder {
 cb.Color = color
 return cb
}

func (cb *CarBuilder) SetEngineSize(engineSize float64) *CarBuilder {
 cb.EngineSize = engineSize
 return cb
}

func (cb *CarBuilder) Build() *Car {
 return &cb.Car
}

Структура CarBuilder включает в себя объект Car, поэтому все его поля доступны построителю.

Структура CarBuilder имеет методы для установки необязательных параметров объекта Car. Каждый метод возвращает указатель на структуру CarBuilder, чтобы обеспечить цепочку методов.

Метод Build структуры CarBuilder возвращает указатель на созданный объект Car.

Вот пример использования CarBuilder:

carBuilder := &CarBuilder{}

car := carBuilder.
    SetMake("Toyota").
    SetModel("Corolla").
    SetYear(2021).
    SetColor("Red").
    SetEngineSize(1.8).
    Build()

fmt.Printf("Make: %s\n", car.Make) // Output: Make: Toyota
fmt.Printf("Model: %s\n", car.Model) // Output: Model: Corolla
fmt.Printf("Year: %d\n", car.Year) // Output: Year: 2021
fmt.Printf("Color: %s\n", car.Color) // Output: Color: Red
fmt.Printf("Engine Size: %.1f\n", car.EngineSize) // Output: Engine Size: 1.8

В этом примере мы создаем объект CarBuilder и используем его методы для установки дополнительных параметров объекта Car.

Наконец, мы вызываем метод Build, чтобы получить окончательный объект Car. Затем мы распечатываем поля объекта Car, чтобы убедиться, что они были заданы правильно.

Расширенные варианты использования шаблона Builder в Go

Шаблон построителя имеет несколько расширенных вариантов использования, которые могут быть полезны в определенных ситуациях.

Теперь мы рассмотрим некоторые расширенные варианты использования шаблона Builder в Go.

Создание интерфейса конструктора

В базовом примере шаблона построителя у нас была одна структура построителя, которая использовалась для создания объекта.

Однако вы можете создать интерфейс построителя, который могут реализовать несколько структур построителя.

Это может быть полезно, когда у вас есть разные типы объектов, которые необходимо построить с использованием одного и того же шаблона.

Допустим, у вас есть два типа автомобилей: электромобили и бензиновые автомобили. Оба типа автомобилей имеют одинаковые необязательные параметры, но разные обязательные параметры.

В этом случае вы можете создать интерфейс CarBuilder, указывающий необходимые методы для сборки автомобиля, а затем создать две структуры, реализующие интерфейс CarBuilder: ElectricCarBuilder и GasolineCarBuilder.

type CarBuilder interface {
 SetMake(make string) CarBuilder
 SetModel(model string) CarBuilder
 SetYear(year int) CarBuilder
 SetColor(color string) CarBuilder
 SetEngineSize(engineSize float64) CarBuilder
 Build() Car
}

type ElectricCarBuilder struct {
 Car
}

type GasolineCarBuilder struct {
 Car
}

И ElectricCarBuilder, и GasolineCarBuilder встраивают структуру Car и реализуют интерфейс CarBuilder.

Затем у них может быть собственная реализация необходимых методов для сборки автомобиля.

func (b *ElectricCarBuilder) SetMake(make string) CarBuilder {
 b.Make = make
 return b
}

func (b *ElectricCarBuilder) SetModel(model string) CarBuilder {
 b.Model = model
 return b
}

func (b *ElectricCarBuilder) SetYear(year int) CarBuilder {
 b.Year = year
 return b
}

func (b *ElectricCarBuilder) SetColor(color string) CarBuilder {
 b.Color = color
 return b
}

func (b *ElectricCarBuilder) SetEngineSize(engineSize float64) CarBuilder {
 b.EngineSize = engineSize
 return b
}

func (b *ElectricCarBuilder) Build() Car {
 return b.Car
}

func (b *GasolineCarBuilder) SetMake(make string) CarBuilder {
 b.Make = make
 return b
}

func (b *GasolineCarBuilder) SetModel(model string) CarBuilder {
 b.Model = model
 return b
}

func (b *GasolineCarBuilder) SetYear(year int) CarBuilder {
 b.Year = year
 return b
}

func (b *GasolineCarBuilder) SetColor(color string) CarBuilder {
 b.Color = color
 return b
}

func (b *GasolineCarBuilder) SetEngineSize(engineSize float64) CarBuilder {
 b.EngineSize = engineSize
 return b
}

func (b *GasolineCarBuilder) Build() Car {
 return b.Car
}

Вот как мы можем создать автомобиль с помощью интерфейса, мы также можем использовать тот же интерфейс для мока.

func CreateCar(builder CarBuilder) Car {
 return builder.
  SetMake("Toyota").
  SetModel("Corolla").
  SetYear(2022).
  SetColor("blue").
  SetEngineSize(2.0).
  Build()
}

func main() {
 electricCarBuilder := &ElectricCarBuilder{}
 gasolineCarBuilder := &GasolineCarBuilder{}

 electricCar := CreateCar(electricCarBuilder)
 gasolineCar := CreateCar(gasolineCarBuilder)

 fmt.Printf("Electric car: %+v\n", electricCar)
 fmt.Printf("Gasoline car: %+v\n", gasolineCar)
}

В этом примере мы создаем ElectricCarBuilder и GasolineCarBuilder и используем их для создания электромобиля и бензинового автомобиля соответственно.

Функция CreateCar принимает интерфейс CarBuilder и задает необходимые поля с помощью методов построителя, прежде чем, наконец, вызвать метод Build для создания объекта Car.

Хлопайте пожалуйста!!

Если вы нашли эту статью полезной, я был бы признателен за хлопки 👏👏👏👏, это мотивирует меня писать больше таких полезных статей в будущем.

Подписывайтесь на меня на Medium, чтобы получать регулярный потрясающий контент и идеи.

Подпишитесь на мою рассылку

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

https://dsysd.beehiiv.com/subscribe

Важные ссылки

Спасибо, что прочитали пост, не забудьте перейти по ссылкам ниже, чтобы увидеть еще больше интересного контента в будущем.

Twitter: https://twitter.com/dsysd_dev
Youtube: https://www.youtube.com/@dsysd-dev< br /> Github: https://github.com/dsysd-dev
Medium: https://medium.com/@dsysd- dev
Электронная почта: [email protected]
Linkedin: https://www.linkedin.com/in/ dsysd-dev/
Информационный бюллетень: https://dsysd.beehiiv.com/subscribe
Gumroad: https://dsysd .gumroad.com/