单例模式很常用,但是在项目中一个对象是否真的有必要设计为单例,需要仔细斟酌,不节制地使用单例是一把双刃剑。
单例使用过多会引入的问题:
- 过于方便调用,虽说这是优点,但有时可能会破坏程序结构,多人开发思想很难统一,越大的项目越容易出现代码边界在多次迭代后越来越模糊;
- 生命周期过长,消耗内存,占用资源。
最优秀的单例写法,直接上代码:
C++版:
Meyers’ Singleton,《Effective C++》系列书籍的作者 Meyers 提出的,属于懒汉模式(该对象生命周期从声明到程序结束),从C++11版本开始是线程安全的。
代码直接拷贝自如下博客,更具体的解释详见:
https://www.cnblogs.com/sunchaothu/p/10389842.html
#include <iostream>
class Singleton
{
public:
~Singleton(){
std::cout<<"destructor called!"<<std::endl;
}
Singleton(const Singleton&)=delete;
Singleton& operator=(const Singleton&)=delete;
static Singleton& get_instance(){
static Singleton instance;
return instance;
}
private:
Singleton(){
std::cout<<"constructor called!"<<std::endl;
}
};
int main(int argc, char *argv[])
{
Singleton& instance_1 = Singleton::get_instance();
Singleton& instance_2 = Singleton::get_instance();
return 0;
}
运行结果:
constructor called!
destructor called!
两个小知识需要说一下:
- 如下写法可以禁用编译器自动生成的函数,是C++11的新特性,如果不用=delete,可以将函数设置为private也可以实现外部调用的禁用。
Singleton(const Singleton&)=delete;
- 如果想记录Singleton::get_instance()的返回值,需要使用引用变量做左值,如果写成下面这样,会调用Singleton的拷贝构造函数,造出第二个对象,所以Singleton拷贝构造函数需要被禁用,直接让这种写法编译不过。
Singleton instance_1 = Singleton::get_instance();
Java版:
延迟加载,用到的时候才会创建对象,JVM保证线程安全。
public class Singleton {
/**
* 类级的内部类,也就是静态的成员式内部类,该内部类的实例与外部类的实例
* 没有绑定关系,而且只有被调用到才会装载,从而实现了延迟加载
*/
private static class SingletonHolder{
/**
* 静态初始化器,由JVM来保证线程安全
*/
private static Singleton instance = new Singleton();
}
/**
* 私有化构造方法
*/
private Singleton(){
}
public static Singleton getInstance(){
return SingletonHolder.instance;
}
}
代码直接拷贝自如下博客,更具体的解释详见:
https://www.cnblogs.com/t0000/p/8250686.html