单例类,通过使用private的构造函数确保一个应用中只产生一个实例,并且是自行实例化。通用代码如下:
public class Singleton{ private static final Singleton singleton = new Singleton(); //限制产生多个对象 private Singleton(){} //通过该方法获取实例对象 public static Singleton getSingleton(){ return singleton; } public static void doSomething(){ } }
单例模式的优缺点:
- 由于单例在内存中只有一个实例,减少内存开支,特别是对象需要频繁创建和销毁时;
- 当单例模式只产生一个对象,当对象的产生需要较多资源,比如读取配置文件、产生其他依赖对象时,可以使用单例模式减少性能开销;
- 可以避免对资源的多重占用,例如一个写文件操作,使用单例,可以避免同时对文件的写操作;
- 设置系统全局访问点,优化和共享资源访问,比如设计一个单例类,处理所有数据表的映射处理。
但是它也有一些缺点:
- 单例类一般没有接口,扩展很困难,而且接口对单例模式来说也没有意义,它要求自行实例化,而接口和抽象类是不能实例化的。
- 对于测试不利。
- 单例模式与单一职责模式有冲突。类应该只实现单个逻辑,而不关心是否是单例,单例模式把“要单例”和业务逻辑融合到一个类中。
使用场景:
- 要求生成唯一的序列号的环境;
- 访问共享资源点或共享数据,例如一个web计数器,不用每次都刷新到数据库中,使用单例模式并确保线程安全;
- 创建一个对象需要消耗的资源过多,比如访问IO或者创建数据库等资源;
- 定义大量静态常量和静态方法的类,比如工具类。
使用注意事项:
在高并发环境下,上述通用代码不会产生多个实例,但如果使用下面的方式创建(懒汉模式),则会出现问题:
//线程不安全类,需要使用synchronize关键字等手段加以同步
public class Singleton{ private static Singleton singleton = null; //限制产生多个对象 private Singleton{} public static Singleton getInstance(){ if(singleton == null){ singleton = new Singleton(); } return singleton; } }
其次,需要考虑对象的复制情况,在java中,对象默认不可复制,除非实现了Cloneable接口,并实现了clone()方法,则可以直接复制出一个新对象,并且不通过构造函数,即使是私有构造函数,这种情况唯一的办法是不要事先Cloneable接口。