Skip to main content

Command Palette

Search for a command to run...

Notes: Go Design Patterns - Factory Pattern

This blog contains the implementation of Factory design pattern using SMS and email notification objects

Published
2 min read
Notes: Go Design Patterns - Factory Pattern

Factory pattern offloads the logic behind the creation of concrete objects. In Factory pattern, we create objects without exposing the creation logic to the client and refer to the newly created object using a common interface.

Let's try to understand this by using a notification system. Let's say we have two methods to deliver notifications to the users, one by SMS and the other by Email. The interface that defines a notification system can look like this:

type iNotificationService interface {
    notify(message string)
}

Now, both SMS and Email will use this interface to implement the notification system.

// sms set up
type sms struct{}

func (s *sms) notify(message string) {
    fmt.Printf("sms sent: %v\n", message)
}

// email set up
type email struct{}

func (e *email) notify(message string) {
    fmt.Printf("email sent: %v\n", message)
}

Now that both methods implement iNotificationService interface, we can create a factory that creates any of these objects by returning the interface:

func notificationServiceFactory(notificationType string) (iNotificationService, error) {
    if notificationType == "sms" {
        return &sms{}, nil // can be improved further with constructors
    } else if notificationType == "email" {
        return &email{}, nil
    } else {
        return nil, fmt.Errorf("invalid notification service")
    }
}

Now, we can have any of these objects we want without thinking about their implementations individually.

Complete code to test:

package main

import "fmt"

type iNotificationService interface {
    notify(message string)
}

// sms set up
type sms struct{}

func (s *sms) notify(message string) {
    fmt.Printf("sms sent: %v\n", message)
}

// email set up
type email struct{}

func (e *email) notify(message string) {
    fmt.Printf("email sent: %v\n", message)
}

func notificationServiceFactory(notificationType string) (iNotificationService, error) {
    if notificationType == "sms" {
        return &sms{}, nil // can be improved further with constructors
    } else if notificationType == "email" {
        return &email{}, nil
    } else {
        return nil, fmt.Errorf("invalid notification service")
    }
}

func main() {
    notificationService1, _ := notificationServiceFactory("sms")
    notificationService1.notify("otp - 007")

    notificationService2, _ := notificationServiceFactory("email")
    notificationService2.notify("password - 12345")
}

More from this blog

btree.dev

28 posts

Hey 👋 , I am a Backend Engineer working at Getir. In this blog, I write about software architecture, distributed systems, and other interesting computer science concepts.