单例模式写法

单例模式,Singleton Pattern,就是保证在程序的整个生命周期中只创建一个类的实例(对象),在设计日志的时候尤为常见。

1 C++中的单例模式

在C++中实现单例模式有很多种方式,这里采用最常见的实现方式之一:基于静态局部变量,Meyers' Singleton。这种方式利用了C++11及以后标准中对静态局部变量初始化的保证,实现了线程安全、懒加载。

class Example {
private:
    Example() = default;
    // 禁用拷贝构造函数和赋值运算符
    Example(const Example&) = delete;
    Example& operator=(const Example&) = delete;
    
public:
    static Example& getInstance() {
        static Example instance;
        return instance;
    }
};

接着来测试一下

int main() {
    Example& a = Example::getInstance();
    Example& b = Example::getInstance();
    if (&a == &b) cout << "a and b are the same instance.\n";
    return 0;
}
  • 懒加载,Lazy Initialization。只有在第一次调用getInstance时才创建实例,而不是程序启动的时候。
  • 线程安全:初始化过程保证了互斥和同步,避免多线程并发。

static关键字

  • static关键字修饰局部变量

函数getInstance中的static关键字修饰了instance这个局部变量指定该变量只能初始化一次,并在之后再次调用该函数的时候保留其状态。这是因为static关键字改变了局部变量的生命周期(Storage Duration),它本应该在函数调用完成之后销毁的,但实际上被保留在了C++内存分布中的静态区,直到程序结束后才释放。尽管如此,其作用域(Scope)仍然局限于其所在的函数内部

  • static修饰成员函数——静态成员函数。在讲解静态成员函数之前,先介绍静态成员变量

静态成员变量,就是被static修饰的类成员变量,有以下几个规则:

  • 必须在类中声明,类外初始化;
  • 被所有类的对象(实例)共享,不属于某一个对象;
  • 也具有public、protected、private三种访问级别,访问的方式和普通的类似;
  • 可以通过三种方式(对象、类、匿名对象)进行访问:
class A {
public:
    static int s_num;	// 默认为0
};
int A::s_num = 2;

int main() {
    A a;
    cout << a.s_num << endl;	// 对象
    cout << A::s_num << endl;	// 类
    cout << A().s_num << endl;	// 匿名对象 突破类域
}

由于静态成员函数没有this指针,不能访问非静态成员变量。因为this指针是属于一个实例的,每一个被创建的实例都拥有其独特的this指针,维护其本身所具有的成员变量。

2 Python实现单例模式

在Python中使用构造方法__new__来控制实例的创建过程,实现单例模式只需要在类中存储和表示一个类的实例__instance,并且加一个判断:类是否有对象。

  • __new__属于魔术方法,不需要手动调用,除了cls接收当前类,其它的参数需要和__init__保持一致。它返回object.__new__(cls)来构造实例。
class Demo:
    __instance = None
    def __new__(cls, *args, **kwargs):
        if not cls.__instance:
            cls.__instance = object.__new__(cls) # or super().__new__(cls)
        return cls.__instance

a = Demo()
b = Demo()
print(a is b)

需要注意的是,__init__可能会被多次调用,从而把原有的成员变量的值给覆盖了,这是和C++不同的地方。上述实现并没有考虑多线程并发的场景,因此在并发场景下需要改进:

from threading import Lock

class Demo:
    __instance = None
    __lock = Lock()
    def __new__(cls):
        if not cls.__instance:
            with cls.__lock:
                cls.__instance = super().__new__(cls)
        return cls.__instance

上述代码并没有测试在并发场景下是否是正确的,未来看看对不对

posted @ 2025-12-05 12:33  skeinz  阅读(0)  评论(0)    收藏  举报