1. สมมติแบบ Singleton

รูปแแบบสมมติแบบ Singleton เป็นรูปแบบการออกแบบที่ใช้สร้างอินสแตนซ์คลาสให้มีเพียงอย่างเดียว และให้จุดเข้าถึงกลางสำหรับการเข้าถึงอินสแตนซ์ดังกล่าว รูปแบบ Singleton มักถูกนำไปใช้ในสถานการณ์ที่ทรัพยากรต้องการถูกร่วมกัน หรือต้องการควบคุมการเข้าถึงอินสแตนซ์ที่แน่นอน

2. ลักษณะและข้อดีของรูปแบบ Singleton

รูปแแบบ Singleton มีลักษณะและข้อดีดังนี้:

  • ต้องการให้คลาสมีอินสแตนซ์อ็อบเจกต์เพียงอย่างเดียว
  • ให้จุดเข้าถึงทั่วโลกสำหรับโค้ดภายนอกที่ต้องการเข้าถึงอินสแตนซ์
  • ป้องกันการสร้างอินสแตนซ์ซ้ำซ้อน ช่วยประหยัดทรัพยากรของระบบ

3. สถานการณ์การใช้งานของรูปแบบ Singleton

รูปแบบ Singleton เหมาะสำหรับสถานการณ์การใช้งานต่อไปนี้:

  • ตัวบันทึกข้อมูล (Loggers): การให้มั่นใจว่ามีเพียงแค่ตัวบันทึกข้อมูลเดียวสำหรับระบบทั้งหมดเพื่อป้องกันการบันทึกข้อมูลซ้ำซ้อน
  • สร้างคลัสเชื่อมต่อฐานข้อมูล (Database Connection Pool): ในสภาพแวดลอมสูง การใช้รูปแบบ Singleton สามารถป้องกันการสร้างและทำลายการเชื่อมต่อฐานข้อมูลบ่อยครั้งได้

4. การประมวลผลของรูปแบบ Singleton ใน Golang

ใน Golang มีวิธีการในการประมวลผลรูปแบบ Singleton หลายวิธี ดังต่อไปนี้คือวิธีที่ใช้บ่อย

4.1 การประมวลผลโดยใช้การเริ่มต้นอย่างเร่งร้อนและการเริ่มต้นช้า

การเริ่มต้นอย่างช้าจะสร้างอินสแตนซ์อ็อบเจกต์เมื่อถูกใช้ครั้งแรก ในขณะที่การเริ่มต้นอย่างเร่งร้อนจะสร้างอินสแตนซ์อ็อบเจกต์เมื่อโปรแกรมเริ่มทำงาน

// การประมวลผลแบบเริ่มต้นอย่างช้าของรูปแบบ Singleton
package singleton

type Singleton struct {
}

var instance *Singleton

func GetInstance() *Singleton {
    if instance == nil {
        instance = &Singleton{}
    }
    return instance
}

// การประมวลผลที่ใช้เริ่มต้นอย่างเร่งร้อนของรูปแบบ Singleton
package singleton

type Singleton struct {
}

var instance *Singleton = &Singleton{}

func GetInstance() *Singleton {
    return instance
}

4.2 ปัญหาด้านความปลอดภัยของสายในรูปแบบ Singleton

วิธีการประมวลผลด้านความปลอดภัยของสายการถ่ายทอดที่ใช้เริ่มต้นอย่างช้าอาจมีปัญหาในสภาพแวดล้อมที่มีการถ่ายทอดที่ใช้หลายสาย เพราะสายการถ่ายทอดที่หลายเส้นอาจเข้าไปในเงื่อนไข if instance == nil พร้อมๆกัน ซึ่งอาจทำให้มีการสร้างอินสแตนซ์หลายๆตัว

4.3 การประมวลผลรูปแบบ Singleton ที่ปลอดภัยต่อสายโดยใช้ sync.Once

การใช้ sync.Once ช่วยให้ต้องมีกิริยาเท่านั้นที่สายโหวตีใช้สำหรับการเริ่มต้นโค้ด ซึ่งจะแก้ไขปัญหาเรื่องความปลอดภัยของสายได้

// การประมวลผลการเริ่มต้นสายที่ปลอดภัยของรูปแบบ Singleton โดยใช้ sync.Once
package singleton

import (
    "sync"
)

type Singleton struct {
}

var instance *Singleton
var once sync.Once

func GetInstance() *Singleton {
    once.Do(func() {
        instance = &Singleton{}
    })
    return instance
}

4.4 การประมวลฯการเริ่มต้นตามแบบเร่งร้านที่ปลอดภัยสายโดยใช้ sync.Mutex

วิธีอีกวิธีหนึ่งในการประมวลผลรูปแบบ Singleton ที่เริ่มต้นอย่างช้าและปลอดภัยต่อสายคือการใช้ 'sync.Mutex' เพื่อล็อคและให้แน่ใจว่ามีเพียงแค่สายโหวตีเดียวที่มีการประมวลการเริ่มต้น

// การประมวลผลการเริ่มต้นอย่างช้าแบบปลอดภัยสายโดยใช้ sync.Mutex ของรูปแบบ Singleton
package singleton

import (
    "sync"
)

type Singleton struct {
}

var instance *Singleton
var mu sync.Mutex

func GetInstance() *Singleton {
    if instance == nil {
        mu.Lock()
        defer mu.Unlock()
        if instance == nil {
            instance = &Singleton{}
        }
    }
    return instance
}