- vừa được xem lúc

[ Design Patterns ] - Builder pattern with Golang

0 0 17

Người đăng: Nguyen Van Tuan

Theo Viblo Asia

Ha Noi, on Thursday 18/09/2023

At the moment, a little speech to give to the present...

image.png

Hà Nội mùa này vắng những cơn mưa
Cái rét đầu đông khăn em hiu hiu gió lạnh
Hoa sữa thôi rơi ta bên nhau một chiều tan lớp
Đường Cổ Ngư xưa chầm chậm bước ta về...😥😥😥

Ha Noi is approaching winter, when there will be no rain. I'm sitting in my room and writing this post. Today's temperature in Ha Noi is 25°C, cloudy, and starting to get colder than previous days. The weather is appropriate for lonely people 😉😉😉

The news about layoffs in big tech is not good for everyone around the world, and it was beginning to affect employees in Vietnam. I hope that by 2023, everything will be back to normal. Best wishes to everyone! 😍😍😍

I. Builder pattern

The Builder pattern is used when the desired product is complex and requires multiple steps to complete. In this case, several construction methods would be simpler than a single monstrous constructor. The potential problem with the multistage building process is that a partially built and unstable product may be exposed to the client. The Builder pattern keeps the product private until it’s fully built.

Reference : Builder pattern

II. Components of the builder pattern

image.png

  1. Product : These are the resultant objects. Products will have different results. It will be determined by how the object is constructed.

  2. Concreate Builder : Provides implementation for Builder. It is an object able to construct other objects. Constructs and assembles parts to build the objects.

  3. Builder : Abstract interface for creating objects (product) and getting concreate builder.

  4. Director : The class will call order-by-step to build objects.

III. Implement

1. The problem

My team must build one application for selling offline fruits to one restaurant. The customer will select fruits and add them to their cart after going to the counter and requiring payment. The employee of the restaurant will scan the QR code of the fruit, and your application will display information about the fruit's price, amount, and discount.
The application must calculate the amount of money that the customer must pay for the restaurant according to the rules below.

Example rules :

Name Amount Price Discount
Orange More than 10 Price = Price - $5
eg : each fruit's price = $49.99 => Price = $49.99 - 5=44.995 = 44.99 Discount = Discount + 2%
eg : each fruit's discount = 10% => Discount = 10 + 2 = 12%
Orange Less than 10 fruit's price fruit's discount
Apple More than 10 Price = Price - $10
eg : each fruit's price = $49.99 => Price = $49.99 - 10=39.9910 = 39.99 Discount = Discount + 5%
eg : each fruit's discount = 10% => Discount = 10 + 5 = 15%
Apple Less than 10 fruit's price fruit's discount

Note : *The restaurant will have far more fruit, and the rules will be far more complicated. *

2. Problem solving

I think you will code as in the example below. We will use if-else to check the fruit's name and process logic for it in each case.

type Output struct { Money float64
} func GetMoney(name string, amount int64, price, discount float64) Output { money := float64(0) if name == "orange" { if amount > 10 { price -= 5 discount += 2 money = price * (discount - discount/100) * float64(amount) } // do anything logical } else if name == "apple" { if amount > 10 { price -= 10 discount += 5 money = price * (discount - discount/100) * float64(amount) } // do anything logical } return Output{Money: money}
}

Sure, it will still work, but when restaurants need to calculate the price, discount, and scale the sale of fruit, our codebase becomes too large, and updating the codebase becomes difficult.

When the restaurant adds one new fruit, updates, or adds one new rule, we must hold a meeting to confirm and update the codebase in a unified manner.

So, to resolve the problem, we will use the builder design pattern.

3. Implement builder design pattern

3.1. ifruit_builder.go : Builder interface

package builder import ( "design-pattern-golang-example/builder-pattern/concreate_builder" "design-pattern-golang-example/builder-pattern/constant" "design-pattern-golang-example/builder-pattern/product"
) type IFruitBuilder interface { SetPrice(in *product.InfoInput) SetDiscount(in *product.InfoInput) SetMoneyPayment(in *product.InfoInput) ToOutputMoney() *product.InfoOutput
} func GetFruitBuilder(fruitName string) IFruitBuilder { switch fruitName { case constant.Orange: return concreate_builder.NewOrangeBuilder() case constant.Apple: return concreate_builder.NewAppleBuilder() } return nil
}

3.2. orange_builder.go: Concreate builder for orange

package concreate_builder import "design-pattern-golang-example/builder-pattern/product" type OrangeBuilder struct { Price float64 Discount float64 MoneyPayment float64
} func NewOrangeBuilder() *OrangeBuilder { return &OrangeBuilder{}
} func (o *OrangeBuilder) SetPrice(in *product.InfoInput) { if in.Amount > 10 { o.Price = in.Price - 5 }
} func (o *OrangeBuilder) SetDiscount(in *product.InfoInput) { if in.Amount > 10 { o.Discount = in.Discount + 2 }
} func (o *OrangeBuilder) SetMoneyPayment(in *product.InfoInput) { o.MoneyPayment = o.Price * (100 - o.Discount/100) * float64(in.Amount)
} func (o *OrangeBuilder) ToOutputMoney() *product.InfoOutput { return &product.InfoOutput{ MoneyPayment: o.MoneyPayment, }
}

3.3. apple_builder.go: Concreate builder for apple

package concreate_builder import "design-pattern-golang-example/builder-pattern/product" type AppleBuilder struct { Price float64 Discount float64 MoneyPayment float64
} func NewAppleBuilder() *AppleBuilder { return &AppleBuilder{}
} func (o *AppleBuilder) SetPrice(in *product.InfoInput) { if in.Amount > 10 { o.Price = in.Price - 10 }
} func (o *AppleBuilder) SetDiscount(in *product.InfoInput) { if in.Amount > 10 { o.Discount = in.Discount + 5 }
} func (o *AppleBuilder) SetMoneyPayment(in *product.InfoInput) { o.MoneyPayment = o.Price * (100 - o.Discount/100) * float64(in.Amount)
} func (o *AppleBuilder) ToOutputMoney() *product.InfoOutput { return &product.InfoOutput{ MoneyPayment: o.MoneyPayment, }
}

3.4. fruit.go : Product

package product type InfoInput struct { Price float64 Discount float64 Amount int64
} type InfoOutput struct { MoneyPayment float64
}

3.5. director.go: Director

package director import ( "design-pattern-golang-example/builder-pattern/builder" "design-pattern-golang-example/builder-pattern/product"
) type Director struct { FruitBuilder builder.IFruitBuilder
} func NewDirector(f builder.IFruitBuilder) *Director { return &Director{ FruitBuilder: f, }
} func (d *Director) BuildOutput(in *product.InfoInput) *product.InfoOutput { d.FruitBuilder.SetPrice(in) d.FruitBuilder.SetDiscount(in) d.FruitBuilder.SetMoneyPayment(in) return d.FruitBuilder.ToOutputMoney()
}

3.6. main.go

package main import ( "fmt" "design-pattern-golang-example/builder-pattern/builder" "design-pattern-golang-example/builder-pattern/constant" "design-pattern-golang-example/builder-pattern/director" "design-pattern-golang-example/builder-pattern/product"
) func main() { in := &product.InfoInput{ Price: 100, Discount: 10, Amount: 15, } builderApple := builder.GetFruitBuilder(constant.Apple) directorApple := director.NewDirector(builderApple) outApple := directorApple.BuildOutput(in) builderOrange := builder.GetFruitBuilder(constant.Orange) directorOrange := director.NewDirector(builderOrange) outOrange := directorOrange.BuildOutput(in) fmt.Printf("Pay for orange : $%v\n", outOrange.MoneyPayment) fmt.Printf("Pay for apple : $%v\n", outApple.MoneyPayment)
}

Ouput :

Pay for orange : $142329
Pay for apple : $134797.5 Process finished with the exit code 0

IV. Source code

Bình luận

Bài viết tương tự

- vừa được xem lúc

gRPC - Nó là gì và có nên sử dụng hay không?

Nhân một ngày rảnh rỗi, mình ngồi đọc lại RPC cũng như gRPC viết lại để nhớ lâu hơn. Vấn đề là gì và tại sao cần nó .

0 0 131

- vừa được xem lúc

Embedded Template in Go

Getting Start. Part of developing a web application usually revolves around working with HTML as user interface.

0 0 56

- vừa được xem lúc

Tạo Resful API đơn giản với Echo framework và MySQL

1. Giới thiệu.

0 0 60

- vừa được xem lúc

Sử dụng goquery trong golang để crawler thông tin các website Việt Nam bị deface trên mirror-h.org

. Trong bài viết này, mình sẽ cùng mọi người khám phá một package thu thập dữ liệu có tên là goquery của golang. Mục tiêu chính của chương trình crawler này sẽ là lấy thông tin các website Việt Nam bị deface (là tấn công, phá hoại website, làm thay đổi giao diện hiển thị của một trang web, khi người

0 0 237

- vừa được xem lúc

Tạo ứng dụng craw dữ liệu bing với Golang, Mysql driver

Chào mọi người . Lâu lâu ta lại gặp nhau 1 lần, để tiếp tục series chia sẻ kiến thức về tech, hôm nay mình sẽ tìm hiểu và chia sẻ về 1 ngôn ngữ đang khá hot trong cộng đồng IT đó là Golang.

0 0 75

- vừa được xem lúc

Golang: Rest api and routing using MUX

Routing with MUX. Let's create a simple CRUD api for a blog site. # All . GET articles/ .

0 0 54