对于某些类,我们希望只有一个对象,无论谁来"new"都返回同一个对象,这样能最大限度的节省资源和使程序更健康单例模式(Singleton Pattern):确保某一个类只有一个实 例,而且自行实例化并向整个系统提供这个实例,这个类称为单例类,它提供全局访问的方 法。单例模式是一种对象创建型模式。
单例模式有三个要点:一是某个类只能有一个实例;二是它必须自行创建这个实例;三是它必须自己可以向整个系统提供这个实例,不再需要额外类替他提供。
单例模式是结构最简单的设计模式一,在它的核心结构中只包含一个被称为单例类的特殊类。
单例模式的实现:
1.饿汉式单例
class EagerSingleton {
private static final EagerSingleton instance = new EagerSingleton();
private EagerSingleton() {
//初始化代码,省略...
}
//该类相关公共成员方法,省略...
public static EagerSingleton getInstance() {
return instance;
}
}
2.懒汉式单例
class LazySingleton {
private static LazySingleton instance = null;
private LazySingleton() {
//初始化代码,省略...
}
//该类相关公共成员方法,省略...
public static LazySingleton getInstance() {
if (instance == null) {
instance = new LazySingleton();
}
return instance;
}
}
3.Initialization Demand Holder (IoDH)单例
class IoDHSingleton {
private IoDHSingleton() {
//初始化代码,省略...
}
private static class HolderClass {
private final static IoDHSingleton instance = new IoDHSingleton();
}
//该类相关公共成员方法,省略...
public static IoDHSingleton getInstance() {
return HolderClass.instance;
}
}
三种方式区别:
懒汉单例:在第一次访问单例类的getInstance方法的时候创建实例,以后再访问单例类的getInstance方法都会返回第一次创建的实例,直到instance被垃圾回收器销毁才会创建新的instance。
缺点:再面对多线程访问的时候需要进行特殊处理,如:线程a和线程b同时访问了getInstance方法,这时候instance为null,由于两个线程访问的时候为null,所以每个线程都会创建一个instance实例,不符合单例模式定义,需要通过双重检查锁定等机制进行控制,这将导致系统性能受到一定影响。
饿汉单例:在单例类被加载的时候创建instance,无需考虑多线程访问问题,从调用速度和反应时间角度来讲,由于单例对象一开始就得以创建,因 此要优于懒汉式单例。以后再访问都会返回这个instance,直到instance被垃圾回收器销毁才会创建新的instance。
缺点:
无论系统在运行时是否需要使用该单例对象,由于在类加载时该 对象就需要创建,因此从资源利用效率角度来讲,饿汉式单例不及懒汉式单例,而且在系统 加载时由于需要创建饿汉式单例对象,加载时间可能会比较长。
IoDH单例:通过在单例类中建立私有内部类来完成创建instance,既可以实现延迟加载,又可以保证线程安全,不影响系统性能,不失为一种最好的Java语言单例模式实现方式。
缺点:编程语言本身的特性相关,很多面向对象 语言不支持IoDH。
单例模式总结
单例模式作为一种目标明确、结构简单、理解容易的设计模式,在软件开发中使用频率相当 高,在很多应用软件和框架中都得以广泛应用。单例模式的主要优点如下:
(1) 单例模式提供了对唯一实例的受控访问。因为单例类封装了它的唯一实例,所以它可以严 格控制客户怎样以及何时访问它。
(2) 由于在系统内存中只存在一个对象,因此可以节约系统资源,对于一些需要频繁创建和销 毁的对象单例模式无疑可以提高系统的性能。
(3) 允许可变数目的实例。基于单例模式我们可以进行扩展,使用与单例控制相似的方法来获 得指定个数的对象实例,既节省系统资源,又解决了单例单例对象共享过多有损性能的问题。
单例模式的主要缺点如下:
(1) 由于单例模式中没有抽象层,因此单例类的扩展有很大的困难。
(2) 单例类的职责过重,在一定程度上违背了“单一职责原则”。因为单例类既充当了工厂角 色,提供了工厂方法,同时又充当了产品角色,包含一些业务方法,将产品的创建和产品的 本身的功能融合到一起。
(3) 现在很多面向对象语言(如Java、C#)的运行环境都提供了自动垃圾回收的技术,因此,如 果实例化的共享对象长时间不被利用,系统会认为它是垃圾,会自动销毁并回收资源,下次 利用时又将重新实例化,这将导致共享的单例对象状态的丢失。
在以下情况下可以考虑使用单例模式:
(1) 系统只需要一个实例对象,如系统要求提供一个唯一的序列号生成器或资源管理器,或者 需要考虑资源消耗太大而只允许创建一个对象。
(2) 客户调用类的单个实例只允许使用一个公共访问点,除了该公共访问点,不能通过其他途 径访问该实例。
评论
发表评论