单例模式简述
1. 单例模式(Singleton Pattern)定义:
Ensure a class has only one instance,and provide a globle point of access to it.(确保一个类只有一个实例,并提供一个全局访问点。)
2. 单例模式使用场景:
有一些对象往往只需要一个,如:线程池(threadpool)、缓存(cache)、对话框、处理偏好设置和注册表的对象、日志对象、打印机、显卡等设备的驱动程序的对象。大体可分为如下几类场景:
[] 要求生成唯一序列号的环境;
[] 在整个项目中需要一个共享访问点或共享数据,如Web页面上的计数器,可以不用把每次刷新都记录到数据库中,使用单例模式保持计数器的值,并确保是线程安全的;
[] 创建一个对象需要消耗的资源过多,如要访问IO和数据库等资源;
[] 需要定义大量的静态常量和静态方法(如工具类)的环境,可以采用单例模式(也可以直接声明为static的方式)。
3.如何实现?
由上面分析可见很多时候一些类确实应该只存在一个实例。那怎么做到这一点呢?通常我们会想到可以靠程序员之间的约定或是利用全局变量,如利用Java的静态变量。
通过程序员之间的约定确实可以办到,通过全局变量也很方便,但是全局变量有其自身的缺点。如将对象赋值给一个全局变量,就必须在程序一开始就创建好对象,这个对象可能会很耗费资源,而程序在这次执行过程中又一直没有用到它,就会造成浪费。利用静态类变量、静态方法和适当的访问修饰符(acess modifier)可以改善情况。
那么我们的单例模式又是怎样处理的呢?它是怎样做到:确保一个类只有一个实例,并提供一个全局访问点?
对象产生一般是通过new关键字完成的(也可以是对象复制、反射等方式产生),如new MyObject();如果另一个对象想创建MyObject时可以再次new MyObject()。所以,如果有一个类是公开的,我们就可以多次实例化它;而如果该类不是公开的,就只有同一个包内的类可以实例化它,但是仍然可以实例化它多次。
使用new关键字创建对象时,都会根据输入的参数调用相应的构造函数。假设我们创建一个含有私有构造器的类呢?如下:
public class MyClass{
private MyClass(){}
}
这样我们可以在MyClass类内调用此构造器,但是由于没有其他类能实例化MyClass,没有MyClass类的实例就不能调用MyClass构造器。结论还是无法调用MyClass构造器,无法在该类里产生一个对象实例。
那如果是这样呢?
public class MyClass{
private MyClass(){}
public static MyClass getInstance(){
}
}
MyClass类有一个静态方法。我们可以这样调用这个方法:
MyClass.getInstance();
这里调用时是用MyClass的类名,而不是对象名,因为getInstance()是个静态方法,即是一个“类”方法,引用一个静态方法,需要使用类名。这样就可以初始化一个MyClass了。
单例模式的通用类图如下:
Singleton类称为单例类,通过使用private的构造函数确保一个应用中只产生一个实例,并且是自行实例化的(在Singleton中自己使用new Singletonn())。
单例模式的通用代码:
public class Singleton{
private static final Singleton singleton = new Singleton();
//限制产生多个对象
private Singleton(){
}
//通过该方法获得实例对象
public static Singleton getSingleton(){
return singleton;
}
//类中其他方法尽量是static
public static void doSomething(){
}
}
单例模式分类
根据实例化对象时机的不同可以将设计模式分为目前较为常用的饿汉式单例和懒汉式单例,但不是只有这两种才算单例模式。饿汉式单例在类加载时就实例化一个对象交给自己的引用,懒汉式在调用取得实例方法时才实例化对象。
代码示例:
//饿汉式
public class Singleton {
private static Singleton singleton = new Singleton();
private Singleton(){}
public static Singleton getInstance(){
return singleton;
}
}
//懒汉式单例
public class Singleton {
private static Singleton singleton;
private Singleton(){}
public static synchronized Singleton getInstance(){
if(singleton==null){
singleton = new Singleton();
}
return singleton;
}
}