一、简介
1、单列模式的定义
单列模式属于 #创建型模式# ,确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例,这个类称为单例类,它提供全局访问的方法。单例模式是一种对象创建型模式。
2、三个要点
(1)某个类只能有一个实例;
(2)它必须自行创建这个实例;
(3)它必须自行向整个系统提供这个实例。
二、实现与测试
1、饿汉单列
public class SingletonEager {
// 无论是否使用都初始化对象,浪费内存
private static final SingletonEager INSTANCE = new SingletonEager();
private SingletonEager(){}
public static SingletonEager getInstance() {
return INSTANCE;
}
}
public class SingletonEagerTest {
@Test
@DisplayName("饿汉式单列对象相等")
void SingletonEagerObjectEqual() {
SingletonEager eagerOne = SingletonEager.getInstance();
SingletonEager eagerTwo = SingletonEager.getInstance();
Assertions.assertEquals(eagerOne, eagerTwo);
}
}
优点:初始化就实例化对象,后续直接使用对象,性能高
缺点:无论是否使用对象都会默认初始化,在不需要使用的时候会浪费内存资源
2、懒汉单列
public class SingletonLazy {
// volatile 屏蔽jvm优化,性能低
private volatile static SingletonLazy INSTANCE = null;
private SingletonLazy(){}
public static SingletonLazy getInstance(){
if (null == INSTANCE){
// 重量级锁,性能低
synchronized (SingletonLazy.class){
// double check
if (null == INSTANCE){
INSTANCE = new SingletonLazy();
}
}
}
return INSTANCE;
}
}
public class SingletonLazyTest {
@Test
@DisplayName("懒汉式单列对象相等")
void SingletonLazyObjectEqual(){
SingletonLazy lazyObjectOne = SingletonLazy.getInstance();
SingletonLazy lazyObjectTwo = SingletonLazy.getInstance();
Assertions.assertEquals(lazyObjectOne, lazyObjectTwo);
}
}
优点:按需使用,需要用到对象的时候再去实例化,节约资源
缺点:性能较差,并发情况下需要等待锁释放
3、IoDH单列(最佳单列)
public class SingletonExample {
private SingletonExample(){}
private static class HolderClass{
private static final SingletonExample instance = new SingletonExample();
}
public static SingletonExample getInstance(){
return HolderClass.instance;
}
}
public class SingletonExampleTest {
@Test
@DisplayName("单列对象相等")
void ObjectEqual(){
SingletonExample objectOne = SingletonExample.getInstance();
SingletonExample objectTwo = SingletonExample.getInstance();
Assertions.assertEquals(objectOne,objectTwo);
}
}
优点:Initialization on Demand Holder
缺点:与编程语言本身的特性相关,很多面向对象语言不支持IoDH
三、总结
1、优点
(1)单例模式提供了对唯一实例的受控访问。因为单例类封装了它的唯一实例,所以它可以严格控制客户怎样以及何时访问它。
(2)由于在系统内存中只存在一个对象,因此可以节约系统资源。对于一些需要频繁创建和销毁的对象,单例模式无疑可以提高系统的性能。
(3)允许可变数目的实例。基于单例模式,开发人员可以进行扩展,使用与控制单例对象相似的方法来获得指定个数的实例对象,既节省系统资源,又解决了由于单例对象共享过多有损性能的问题。(注:自行提供指定数目实例对象的类可称之为多例类。)
2、缺点
(1)由于单例模式中没有抽象层,因此单例类的扩展有很大的困难。
(2)单例类的职责过重,在一定程度上违背了单一职责原则。因为单例类既提供了业务方法,又提供了创建对象的方法(工厂方法),将对象的创建和对象本身的功能耦合在一起。
(3)现在很多面向对象语言(如Java、C#)的运行环境都提供了自动垃圾回收技术,因此,如果实例化的共享对象长时间不被利用,系统会认为它是垃圾,会自动销毁并回收资源,下次利用时又将重新实例化,这将导致共享的单例对象状态的丢失。
3、适用场景
(1)系统只需要一个实例对象。例如,系统要求提供一个唯一的序列号生成器或资源管理器,或者需要考虑资源消耗太大而只允许创建一个对象。
(2)客户调用类的单个实例只允许使用一个公共访问点。除了该公共访问点,不能通过其他途径访问该实例。