原文地址
在之前的博客中,我们讨论了建造者模式的结构。在这篇博客中,让我们来了解一下建造者参数。
为什么需要建造者参数
建造者参数帮助我们直接限制结构体属性和函数的使用。有时我们希望限制用户直接访问结构体的属性和函数。 我们为它们提供api。
直接上代码
假设,我们需要创建一个可以发送邮件的新功能,你不希望你的开发者破坏你的邮件对象。你用建造者参数隐藏它。
//RunBuilderParamter example
func RunBuilderParamter() {
SendEmail(func(b *EmailBuilder) {
b.
To("World@gmail.com").
From("me@gmail.com").
Subject("Hello world").
Body("Sample body for a dummy email")
})
}
以上代码,我们使用一个辅助函数SendEmail,它接受一个func (action)作为参数,并执行一些成员函数,如To(value string),From(value string)等。
另外,请注意,我们不能访问email结构体,也不能访问发送电子邮件的实际发送函数。
我们首先创建一个私有结构体和一个私有函数:
type email struct {
from, to, subject, body string
}
func sendEmail(email *email) {
// logic to send email
fmt.Println("email sent ...")
fmt.Printf("To:%s,\nSubject:%s\n%s\nRegards,\n%s\n", email.to, email.subject, email.body, email.from)
}
现在我们定义建造者结构和辅助函数:
//EmailBuilder struct
type EmailBuilder struct {
email email
}
type action func(builder *EmailBuilder)
//SendEmail function is for client to send email
func SendEmail(action action) {
builder := EmailBuilder{}
action(&builder)
sendEmail(&builder.email)
}
最后,定义成员函数:
//To sets the email's "To" address
func (eb *EmailBuilder) To(value string) *EmailBuilder {
//basic validation
if !strings.Contains(value, "@") {
panic("Invalid email")
}
eb.email.to = value
return eb
}
//From sets the email's "From" address
func (eb *EmailBuilder) From(value string) *EmailBuilder {
//basic validation
if !strings.Contains(value, "@") {
panic("Invalid email")
}
eb.email.from = value
return eb
}
//Body sets the email's "Body"
func (eb *EmailBuilder) Body(value string) *EmailBuilder {
eb.email.body = value
return eb
}
//Subject sets the email's "Subject"
func (eb *EmailBuilder) Subject(value string) *EmailBuilder {
eb.email.subject = value
return eb
}
完整代码如下:
package main
import (
"fmt"
"strings"
)
// Example - Builder Parameter
type email struct {
from, to, subject, body string
}
type action func(builder *EmailBuilder)
//EmailBuilder struct
type EmailBuilder struct {
email email
}
func sendEmail(email *email) {
// logic to send email
fmt.Println("email sent ...")
fmt.Printf("To:%s,\nSubject:%s\n%s\nRegards,\n%s\n", email.to, email.subject, email.body, email.from)
}
//SendEmail function is for client to send email
func SendEmail(action action) {
builder := EmailBuilder{}
action(&builder)
sendEmail(&builder.email)
}
//To sets the email's "To" address
func (eb *EmailBuilder) To(value string) *EmailBuilder {
//basic validation
if !strings.Contains(value, "@") {
panic("Invalid email")
}
eb.email.to = value
return eb
}
//From sets the email's "From" address
func (eb *EmailBuilder) From(value string) *EmailBuilder {
//basic validation
if !strings.Contains(value, "@") {
panic("Invalid email")
}
eb.email.from = value
return eb
}
//Body sets the email's "Body"
func (eb *EmailBuilder) Body(value string) *EmailBuilder {
eb.email.body = value
return eb
}
//Subject sets the email's "Subject"
func (eb *EmailBuilder) Subject(value string) *EmailBuilder {
eb.email.subject = value
return eb
}
//RunBuilderParamter example
func RunBuilderParamter() {
SendEmail(func(b *EmailBuilder) {
b.
To("World@gmail.com").
From("me@gmail.com").
Subject("Hello world").
Body("Sample body for a dummy email")
})
}
说明
当调用SendEmail函数的时候,会创建一个建造者对象EmailBuilder,并将这个对象的引用,作为参数传给action匿名函数。匿名函数会调用建造者的成员函数To、From、Subject和Body完成私有email对象创建,最后调用私有函数sendEmail发送邮件。
用户可以使用这个API,而不必担心创建复杂对象的实现和验证逻辑。