This pattern restricts instantiation of a class to a single instance and provides global access point to that instance.
This pattern is used when:
The pattern operates with only one entity:
Singleton - provides access to the instance over Instance method and ensures that there is only one instance exists.
package main
import "errors"
var alreadyInstantiated = false
var instance *ExampleManufacturer = nil
type Manufacturer interface {
RequestGPU() GPU
RequestMotherboard() Motherboard
}
type GPU struct{}
type Motherboard struct{}
type ExampleManufacturer struct {
GPUs []GPU
Motherboards []Motherboard
}
func NewExampleManufacturer() (*ExampleManufacturer, error) {
if alreadyInstantiated {
return nil, errors.New("already instantiated")
}
instance = &ExampleManufacturer{
GPUs: make([]GPU, 3),
Motherboards: make([]Motherboard, 2),
}
return instance, nil
}
func (m *ExampleManufacturer) RequestGPU() (*GPU, error) {
if len(m.GPUs) == 0 {
return nil, errors.New("no GPUs left")
}
gpu := m.GPUs[0]
m.GPUs = m.GPUs[1:]
return &gpu, nil
}
func (m *ExampleManufacturer) RequestMotherboard() Motherboard {}
func (m *ExampleManufacturer) Instance() *ExampleManufacturer {
if alreadyInstantiated {
return instance
}
}
Python is more of an OOP language and provides more OOP features than Golang, so the implementation of a singleton in Python is more concise and canonical.
import random
class SingletonError(Exception):...
class ExampleManufacturer:
__instance = None
def __new__(cls):
if cls.__instance is not None:
raise SingletonError("already instanciated")
cls.__instance = super().__new__(cls)
return cls.__instance
def __init__(self):
self.GPUs: list[int] = [random.randint(1, 5) for _ in range(5)]
self.Motherboards: list[int] = [random.randint(1, 5) for _ in range(5)]
@classmethod
def instance(cls):
return cls.__instance
def main():
manufacturer = ExampleManufacturer()
print(manufacturer.GPUs)
try:
again = ExampleManufacturer()
except SingletonError:
print("cant instantiate another instance of a class")
again = ExampleManufacturer.instance()
print(again.GPUs)
if __name__ == '__main__':
main()