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

Примечание. Чтобы эффективно понять шаблон Builder с фасетами, прочитайте предыдущий блог Шаблон Builder.

Грани означают one side of something many-sided. Например, полированный алмаз. У него много сторон, так же как и в случае, когда для создания экземпляра в целом требуется несколько сборщиков.

Сценарий

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

Во время выставления счетов необходимо создать новый объект Bill, и счет в основном включает две детали: данные пользователя и данные заказа.

Таким образом, мы должны реализовать два новых экземпляра, а именно User и Order, используя шаблон Builder.

type Order struct {
    ProductName, Address, Phone string
    Price                       float32
}
type OrderBuilder struct {
  *BillBuilder
}
func NewOrderBuilder(firstname, lastname string) *OrderBuilder {
    return &OrderBuilder{}
}
func (ob *OrderBuilder) WhichProduct(productName string) *OrderBuilder {
    ob.bill.Order.ProductName = productName
    return ob
}
func (ob *OrderBuilder) Price(price float32) *OrderBuilder {
    ob.bill.Order.Price = price
    return ob
}
func (ob *OrderBuilder) DeliverAt(address string) *OrderBuilder {
    ob.bill.Order.Address = address
    return ob
}
func (ob *OrderBuilder) ConnectOn(phone string) *OrderBuilder {
    ob.bill.Order.Phone = phone
    return ob
}

Экземпляр структуры Order может быть создан путем реализации OrderBuilder, и он предоставляет такие методы, как WhichProduct(), Price(), DeliverAt() и ConnectOn() для установки сведений о заказе в объект Order.

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

type User struct {
    Firstname, Lastname, Address, Phone string
}
type UserBuilder struct {
    *BillBuilder
}
func (ub *UserBuilder) Who(firstname, lastname string) *UserBuilder {
    ub.bill.User.Firstname = firstname
    ub.bill.User.Lastname = lastname
    return ub
}
func (ub *UserBuilder) StaysAt(address string) *UserBuilder {
    ub.bill.User.Address = address
    return ub
}
func (ub *UserBuilder) ConnectOn(phone string) *UserBuilder {
    ub.bill.User.Phone = phone
    return ub
}

Пользовательский объект может быть создан с использованием приведенной выше реализации, где методы Who(), StaysAt() и ConnectOn() будут использоваться для заполнения объекта необходимой User информацией.

Мы реализовали UserBuilder и OrderBuilder для создания экземпляров User и Order. Теперь нам нужно включить оба объекта в один, чтобы веб-сайт мог генерировать Bill.

Для этого нам понадобится еще один билдер для создания объекта Bill. Давайте перейдем к реализации BillBuilder, который будет накапливать два других компоновщика для создания объекта Bill в целом.

type Bill struct {
    User
    Order
}
type BillBuilder struct {
    bill *Bill
}
func NewBillBuilder() *BillBuilder {
    return &BillBuilder{&Bill{}}
}
func (bb *BillBuilder) SetProfile() *UserBuilder {
    return &UserBuilder{bb}
}
func (bb *BillBuilder) SetOrder() *OrderBuilder {
    return &OrderBuilder{bb}
}
func (bb *BillBuilder) Build() *Bill {
    return bb.bill
}

В приведенном выше коде оба компоновщика включены в один для создания объекта Bill в целом.

Давайте посмотрим на основной метод для вызова Builders в функции main() и создания счета.

func main() {
    bill := NewBillBuilder().
                SetProfile().
                    Who("Foo", "Bar").
                    StaysAt("ABC City").
                    ConnectOn("0090090090").
                SetOrder().
                    WhichProduct("XYZ Product").
                    Price(999).
                    DeliverAt("ABC City").
                    ConnectOn("5555555555")
                .Build()
    
    fmt.Println("Bill Object: ", *bill)
}

Здесь, в main(), с помощью API, предоставленных строителями, мы можем поместить детали в соответствующие объекты и сгенерировать счет, который будет предоставлен покупателю и в дальнейшем будет использоваться во время отгрузки для доставки заказанного продукта.

Заключение

В этом шаблоне проектирования Builder-Facets мы узнали, как реализовать Builder pattern, когда необходимо создать multiple instances для построения single parent instance в целом.

Здесь мы создали несколько объектов, используя шаблон построителя, которые представляют собой размеры (фасеты), которые будут объединены в один родительский объект.

Удачного программирования…!!!

Ещё больше: