Notes: Go Design Patterns - Builder Pattern

Notes: Go Design Patterns - Builder Pattern

This blog contains the implementation of Builder design pattern by building Message object using JSON and XML builders

ยท

2 min read

Table of contents

No heading

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)
}
ย