Notes: Go Design Patterns - Builder Pattern
This blog contains the implementation of Builder design pattern by building Message object using JSON and XML builders
Table of contents
No headings in the article.
Builder pattern builds complex objects using simple objects and using a step-by-step approach. This type of design pattern comes under creational pattern.
In our example, we are building Message
.
type Message struct {
Data string
Format string
}
To build message we require some fields like recipient, sender, and content. So, builders should follow MessageBuilder
interface.
type MessageBuilder interface {
SetRecipient(recipient string)
SetSender(sender string)
SetContent(content string)
BuildMessage() (*Message, error) // returns the built message
}
Now, we have used two different kinds of builders JSONMessageBuilder
and XMLMessageBuilder
to build messages in JSON and XML formats respectively.
Now, to build message without knowing about the concrete type, we have a director which takes MessageBuilder
interface objects as input and gives a concrete-built Message
. We call our director Sender
and here is what it looks like:
type Sender struct{}
func (s *Sender) BuildMessage(builder MessageBuilder) (*Message, error) {
builder.SetRecipient("Kshitij Kumar")
builder.SetSender("Nidhi Pandey")
builder.SetContent("Where is my birthday gift?")
return builder.BuildMessage()
}
Complete working code where you can see the complete result:
package main
import (
"encoding/json"
"encoding/xml"
"fmt"
)
// we'll be building "Message"
type Message struct {
Data string
Format string
}
// builder interface to build Message
type MessageBuilder interface {
SetRecipient(recipient string)
SetSender(sender string)
SetContent(content string)
BuildMessage() (*Message, error) // returns the built message
}
type CommonMessageBuilderFields struct {
MessageRecipient string `json:"recipient" xml:"recipient"`
MessageSender string `json:"sender" xml:"sender"`
MessageContent string `json:"content" xml:"content"`
}
// JSON message builder
type JSONMessageBuilder struct {
CommonMessageBuilderFields
}
func (b *JSONMessageBuilder) SetRecipient(recipient string) {
b.MessageRecipient = recipient
}
func (b *JSONMessageBuilder) SetSender(sender string) {
b.MessageSender = sender
}
func (b *JSONMessageBuilder) SetContent(content string) {
b.MessageContent = content
}
func (b *JSONMessageBuilder) BuildMessage() (*Message, error) {
data, err := json.Marshal(b)
if err != nil {
return nil, err
}
return &Message{Data: string(data), Format: "JSON"}, nil
}
// XML message builder
type XMLMessageBuilder struct {
CommonMessageBuilderFields
}
func (b *XMLMessageBuilder) SetRecipient(recipient string) {
b.MessageRecipient = recipient
}
func (b *XMLMessageBuilder) SetSender(sender string) {
b.MessageSender = sender
}
func (b *XMLMessageBuilder) SetContent(content string) {
b.MessageContent = content
}
func (b *XMLMessageBuilder) BuildMessage() (*Message, error) {
data, err := xml.Marshal(b)
if err != nil {
return nil, err
}
return &Message{Data: string(data), Format: "XML"}, nil
}
// director of the message builder
type Sender struct{}
// this builds concrete message
func (s *Sender) BuildMessage(builder MessageBuilder) (*Message, error) {
builder.SetRecipient("Kshitij Kumar")
builder.SetSender("Nidhi Pandey")
builder.SetContent("Where is my birthday gift?")
return builder.BuildMessage()
}
func main() {
sender := &Sender{}
jsonMsg, err := sender.BuildMessage(&JSONMessageBuilder{})
if err != nil {
panic(err)
}
fmt.Printf("%#v\n\n", jsonMsg)
xmlMsg, err := sender.BuildMessage(&XMLMessageBuilder{})
if err != nil {
panic(err)
}
fmt.Printf("%#v\n", xmlMsg)
}