Singleton Design Pattern

The Singleton pattern is a creational design pattern that ensures a class has only one instance and provides a global access point to it.

In software development, there are situations where we need to restrict the instantiation of a class to a single object. This is particularly useful when dealing with shared resources or managing global state.

The Singleton pattern is implemented by defining a class with a private constructor and a static method. The first time the static method is called, it creates a new instance of the class. In subsequent calls, it returns the existing instance.

The Singleton pattern provides the following benefits:

  • Ensures that there is only one instance of a class in the application.
  • Provides a global access point to that instance.
  • Delays the initialization of the instance, improving performance and resource utilization.

The following are two implementations of the Singleton pattern in Go, each demonstrating how to connect to a database:

Hungry Singleton

In Go language, the Hungry Singleton pattern is a design pattern that creates and initializes an object at program startup. Here is how to rewrite the getDB() function using the Hungry Singleton pattern:

package main

import (
	"fmt"
	"sync"

	"gorm.io/driver/mysql"
	"gorm.io/gorm"
)

type Member struct {
	ID   string `gorm:"primaryKey;size:16"`
	Name string `gorm:"size:255"`
	Age  int64  `gorm:"size:10"`
}

var db *gorm.DB

func init() {
	fmt.Println("init")
	db = func() *gorm.DB {
		dsn := "user:pw@tcp(127.0.0.1:3306)/database?charset=utf8mb4&parseTime=True&loc=Local"
		db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
		if err != nil {
			panic("Failed to connect to database: " + err.Error())
		}
		fmt.Println("Connection to database!")
		return db
	}()
}

var o sync.Once

func getDB() *gorm.DB {
	return db
}

func main() {
	fmt.Println("main")
	Db := getDB()
	fmt.Println("addr", &Db, Db)
	var members = Member{ID: "1"}
	Db.Find(&members)
	fmt.Println(members)

	Db2 := getDB()
	fmt.Println("addr", &Db2, Db2)
	var members2 = Member{ID: "2"}
	Db2.Find(&members2)
	fmt.Println(members2)
}

Lazy Singleton

In Go language, the Lazy Singleton pattern is a design pattern that creates and initializes an object only when it is first needed. Here is how to rewrite the getDB() function using the Lazy Singleton pattern:

package main

import (
	"fmt"
	"sync"

	"gorm.io/driver/mysql"
	"gorm.io/gorm"
)

type Member struct {
	ID   string `gorm:"primaryKey;size:16"`
	Name string `gorm:"size:255"`
	Age  int64  `gorm:"size:10"`
}

var (
	db *gorm.DB
	o  sync.Once
)

func getDB() *gorm.DB {
	o.Do(func() {
		db = func() *gorm.DB {
			dsn := "user:password@tcp(127.0.0.1:3306)/database?charset=utf8mb4&parseTime=True&loc=Local"
			db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
			if err != nil {
				panic("Failed to connect to database: " + err.Error())
			}
			fmt.Println("Connection to database!")
			return db
		}()
	})
	return db
}

func main() {
	fmt.Println("main")
	Db := getDB()
	fmt.Println("addr", &Db, Db)
	var members = Member{ID: "1"}
	Db.Find(&members)
	fmt.Println(members)

	Db2 := getDB()
	fmt.Println("addr", &Db2, Db2)
	var members2 = Member{ID: "2"}
	Db2.Find(&members2)
	fmt.Println(members2)
}