什么是单例模式
确保一个类只有一个实例,而且自行实例化并向整个系统提供整个实例。
单例模式的优点
- 由于单例模式在内存中只存在一个实例,可以减少内存的开支,特别是对一个对象需要频繁的创建、销毁,而且创建和销毁的性能又无法优化时,单例模式的优势就非常明显;
- 由于单例模式只生成一个实例,所以减少了系统的性能开销,当一个对象的产生需要较多的资源时,如读取配置、产生其他依赖对象时,则可以通过在启用时直接产生一个单例对象,然后永久驻留内存的方式来解决;
- 单例模式可以避免对资源的多重利用,例如对一个写文件动作,由于只有一个实例存在内存中个,避免了对同一资源文件的同时操作;
- 单例模式可以在系统设置全局的访问点,优化和共享资源访问,例如设计一个单例类,负责所有数据库表的映射。
单例模式的缺点
- 无法创建子类,扩展困难;
- 单例模式对测试不利。在并行开发环境中,如果采用单例模式的类没有完成,是不能进行测试的。单例模式的类通常不会实现接口,这也妨碍了使用mock的方式虚拟一个对象;
- 单例模式与单一职责原则冲突。一个类应该只实现一个逻辑,而不关心它是否是单例的,是不是单例模式取决于环境,单例模式把“要单例”和业务逻辑融合在一起。
单例模式的两种表现形式
饿汉模式:类加载时,就进行对象实例化;
package designmodel;
/**
* 饿汉式单例模式
* 该类构造方法为私有,所以不能被继承
*
*/
public class HungarySingleton {
//声明静态的对象singleton,在加载时就创建该对象
private static HungarySingleton _singleton = new HungarySingleton();
//申明私有的构造方法,避免外界利用构造方法创建出任意多的实例
private HungarySingleton(){}
//通过静态方法获得实例对象
public static HungarySingleton getInstance(){
return _singleton;
}
}
懒汉模式:第一次引用类时,才进行对象实例化。
package designmodel;
/**
* 懒汉式单例类,在第一次被调用时才创建实例
*
*/
public class LazySingleton {
//声明静态的对象singleton
private static LazySingleton _singleton = null;
//申明私有的构造方法,避免外界利用构造方法创建出任意多的实例
private LazySingleton(){}
//将该方法进行同步,避免多线程访问时创建多个实例对象
synchronized public static LazySingleton getInstance(){
//当实例对象为空,则创建单例对象
if(_singleton == null){
_singleton = new LazySingleton();
}
return _singleton;
}
}
饿汉式单例类与懒汉单例类之间的区别
- 饿汉式单例类在类被加载时就实例化,而懒汉式单例类在第一次引用时才实例化;
- 从资源利用率来说,饿汉模式稍差一些,但从反应速度和反应时间角度来讲,饿汉模式单例类则比懒汉式单例类稍好;
- 饿汉式单例类可以在Java中实现,但不易在C++内实现。
单例模式的应用场景
- 要求生成唯一的序列号环境;
- 在整个项目中需要一个共享的访问点或共享数据;
- 创建一个对象需要消耗的资源过多,如访问IO和数据库资源;
- 需要定义大量的静态常量和静态方法的环境。