单例设计

130 阅读1分钟

单例模式 保证一个类仅有一个实例,并提供一个访问它的全局访问点

实现 声名一个变量,在第一次创建对象的时候返回该对象并将该对象赋值给该变量,下次实例化对象时判断该变量如果不为 null/nil 则直接返回该变量存储的对象

Golang

第一种方式(多线程下不安全,可能会创建多个对象)

package main

import "fmt"

type Config struct{
	Host string
	Port int
}

var config *Config

func getConfig() *Config {
	if config == nil {
		config = &Config{
			Host: "127.0.0.1",
			Port: 3306,
		}
		return config
	}
	return config
}

func main() {
	c1 := getConfig()
	c2 := getConfig()

	fmt.Println(c1==c2)
}

第二种方式,加锁(性能稍有影响,因为每次都要加锁)

package main

import (
	"fmt"
	"sync"
)

type Config struct{
	Host string
	Port int
}

var config *Config

var mu sync.Mutex
func getConfig() *Config {
	mu.Lock()
	defer mu.Unlock()

	if config == nil {
		config = &Config{
			Host: "127.0.0.1",
			Port: 3306,
		}
		return config
	}
	return config
}

func main() {
	c1 := getConfig()
	c2 := getConfig()

	fmt.Println(c1==c2)
}

第三种方式 sync.Once, 推荐使用

package main

import (
	"fmt"
	"sync"
)

type Config struct{
	Host string
	Port int
}

var config *Config

var once sync.Once
func getConfig() *Config {
	once.Do(func() {
		config = &Config{
			Host: "127.0.0.1",
			Port: 3306,
		}
	})
	return config
}

func main() {
	c1 := getConfig()
	c2 := getConfig()

	fmt.Println(c1==c2)
}

Python

python 要求的单例模式 __init__ 方法里的逻辑也只能调用一次,只需要加个 __flag 判断一下就好

class Server:
    __instance = None
    __flag = False
    def __new__(cls, *args, **kwargs):
        if cls.__instance is None:
            cls.__instance = super().__new__(cls)
        return cls.__instance

    def __init__(self):
        if not self.__flag:
            print('exec init')
            Server.__flag = True

s1 = Server()
print(s1)

s2 = Server()
print(s2)

print(s1 == s2)