设计模式——单例模式

87 阅读3分钟

一.定义

    确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。

二.类图

image.png

  • Singleton单例类。通过使用private的构造函数确保类在一个应用只产生一个实例,并且是自行实例化(在Singleton中自己使用new Singleton())。

三.优点

  • 由于单例模式在内存中只有一个实例,减少了内存开支,特别是一个对象需要频繁地创建、销毁时,而且创建或销毁时性能又无法优化,单例模式的性能优势就比较明显。
  • 避免对资源的多重占用,例如一个写文件动作,由于只有一个实例存在内存中,避免对同一个资源文件的同时写操作。
  • 可以在系统设置全局的访问点,优化和共享资源访问。

四.缺点

  • 单例模式一般没有接口,扩展很困难,除了修改代码基本上没有第二种途径可以实现。
  • 单例模式对测试是不利的。并行开发环境中,如果单例模式没有完成,是不能进行测试的,没有接口也不能使用mock的方式虚拟一个对象。
  • 单例模式与单一职责原则有冲突。单例模式把“要单例”和业务逻辑融合在一个类中。

五.使用场景

  • 要求生成唯一序列号的环境。
  • 整个项目中需要一个共享访问点或共享数据,例如一个Web页面上的计数器,可以不用把每次刷新都记录到数据库中,使用单例模式保持计数器的值,并确保是线程安全的。
  • 创建一个对象需要消耗的资源过多,如要访问IO和数据库等资源
  • 需要定义大量静态常量和静态方法(工具类)的环境,可以采用单例模式,当然,也可以直接声明为static的方式。

六.注意事项

  • 高并发情况下,注意单例模式的线程同步问题。
  • 考虑对象复制的情况。在Java中,对象默认是不可以被复制的,若实现了Cloneable接口,并实现了clone方法,则可以直接通过对象复制方式创建一个新对象,对象复制时不用调用类的构造函数,因此即使是私有的构造函数,对象依然可以被复制。一般情况下,类复制的情况不需要考虑,最好的做法是单例类不要实现Cloneable接口。
  • 注意JVM的垃圾回收机制,如果一个单例对象在内存中长久不使用,JVM就认为这个对象是一个垃圾,在CPU资源空闲的情况下该对象会被清理掉,下次调用时就需要重新产生一个对象,这种情况下可以由容器管理单例的生命周期。

七.扩展

    产生固定数量对象的模式就叫做有上限的多例模式。多例模式在设计时可决定在内存中有多少个实例,方便系统进行扩展,修正单例可能存在的性能问题,提高系统的响应速度。例如读取文件,我们可以在系统启动时完成初始化工作,在内存中启动固定数量的reader实例,然后在需要读取文件时就可以快速响应。