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
}