1.什么是单例模式??
单例模式是一种比较普遍和简单的模式,在我们的程序中经常会用到。简单的说就是,单例模式就是让一个类永远只对外发布唯一的实例(Instance)。
2.什么情况下使用单例模式??
比如一个连接数据库的系统,使用连接池,那么连接池管理器一定是个单例类。
取系统配置,每次只要读取一次,利用单子模式每次不用实例化对象,直接返回对象引用就可以了。
购物车,一个用户登录时就给其实例化一个购物车,它直到这个用户退出,只能用一 个,这个购物车对象就应采用单子模式设计!
3.为什么使用单例模式?
1. Singleton设计模式保证一个application中就至多只有一个instance, 注意这里界定的是一个application, 而不是一个System.如果不是一个application的话,就不能够保证了。例如:在分布式环境下,虽然单服务器端实现了Singleton,但 是多服务器端(System)就有可能不能保证是Singelton。
保证application中实现该模式的Singleton 类至多只有一个instance, 可以在一定范围内更好地确定业务逻辑, 尤其是那些保证现实生活中application中只有一个的概念。例如前面说的 数据库连接池就是一个典型;
2. Singleton设计模式并不能保证节省资源,这是一点需要澄清的。如果要节省资源,大可不必使用Singleton设计模式,Singleton的设计目标并不是为了节省资源,而且为了保证全局性的逻辑统一;
3. Singleton设计模式与其他设计模式(如 Factory设计模式)的联合使用基本上已经成为了一种“普遍”的技巧,对Singleton的熟悉可以帮助我们在理解他人工作上和相互交流上带来方便。
4.单例模式分三种:懒汉式单例、饿汉式单例、登记式单例三种。
一、懒汉式单例
在类被加载的时候,唯一实例已经被创建。这个设计模式在Java中容易实现,在别的语言中难以实现。
public class LazySingleton {
private static LazySingleton m_intance=null; //私有静态对象,加载时候不做初始化
private LazySingleton(){ //私有构造方法,避免外部创建实例
}
synchronized public static LazySingleton getInstance(){ //静态工厂方法,返回此类的唯一实例.
if(m_intance==null){
m_intance=new LazySingleton(); //当发现实例没有初始化的时候,才初始化.
}
return m_intance;
}
}
二、饿汉式单例
在类加载的时候不创建单例实例。只有在第一次请求实例的时候的时候创建,并且只在第一次创建后,以后不再创建该类的实例。
public class EagerSingleton {
private static final EagerSingleton m_instance = new EagerSingleton();//私有的(private)唯一(static final)实例成员,在类加载的时候就创建好了单例对象
private EagerSingleton() {//私有构造方法,避免外部创建实例
}
public static EagerSingleton getInstance() {//静态工厂方法,返回此类的唯一实例.
return m_instance;
}
}
三、登记式单例
这个单例实际上维护的是一组单例类的实例,将这些实例存放在一个Map(登记薄)中,对于已经登记过的实例,则从工厂直接返回,对于没有登记的,则先登记,而后返回。
public class RegSingleton {
private static Map<String, RegSingleton> m_registry = new HashMap();//登记薄,用来存放所有登记的实例
//在类加载的时候添加一个实例到登记薄
static {
RegSingleton x = new RegSingleton();
m_registry.put(x.getClass().getName(), x);
}
protected RegSingleton() {//受保护的默认构造方法
}
public static RegSingleton getInstance(String name) {//静态工厂方法,返回指定登记对象的唯一实例;
if (name == null) {
name = "RegSingleton";
}
if (m_registry.get(name) == null) {//对于已登记的直接取出返回,对于还未登记的,先登记,然后取出返回
try {
m_registry.put(name, (RegSingleton) Class.forName(name).newInstance());
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
return m_registry.get(name);
}
public String about() {// 一个示意性的商业方法
return "Hello,I am RegSingleton!";
}
}
5.简单且线程安全的两个单例模式
- public class Singleton2 {
- private static Singleton2 instance = new Singleton2();
- private Singleton2(){
- }
- public static Singleton2 getInstance(){
- return instance;
- }
- }
- public class Singleton { // 单例模式创新!google的ioc作者写的。只有在调用的时候才会初始化!而且线程安全
- static class SingletonHolder {
- static Singleton instance = new Singleton();
- }
- public static Singleton getInstance() {
- return SingletonHolder.instance;
- }
- }
PS:1、实例变量应该是静态的私有的。
2、外部调用该实例时,不是通过类的构造方法,而是通过一个getInstance()这样的静态方法来创建该类的唯一实例。
3、默认的构造方法应该是私有的,没有强行规定,但觉得这样子自绝后路的办法未尝不可取 :P
4、单例模式并不是线程安全的,要实现这一点,必须在getTheSpoon()方法前面添加一个同步关键字synchronized。