模式定义
单例模式(Singleton Pattern):单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例,这个类称为单例类,它提供全局访问的方法。单例模式的要点有三个:一是某个类只能有一个实例;二是它必须自行创建这个实例;三是它必须自行向整个系统提供这个实例。单例模式是一种对象创建型模式。
模式结构
单例模式只包含一个Singleton(单例角色);在单例类的内部实现只生成一个实例,同时它提供一个静态的getInstance()工厂方法,让客户可以使用它的唯一实例;为了防止在外部对其实例化,将其构造函数设为私有;在单例类内部定义了一个Singleton类型的静态对象,作为外部共享的唯一实例。
实例
在现实生活中,居民身份证号码具有唯一性,同一个人不允许有多个身份证号码,第一次申请身份证时将给居民分配一个身份证号,如果之后因为遗失等原因补办时,还是使用原来的身份证号码,不会产生新的号码。现使用单例模式模拟该场景。
该实例类图如下所示:
public class IdentityCardNo {
private static IdentityCardNo instance;
private String no;
private IdentityCardNo()
{ }
public static IdentityCardNo getInstance() {
if (instance == null) {
System.out.println("第一次办理身份证,分配新号码");
instance = new IdentityCardNo();
instance.setIdentityCardNo("345963611245369");
}
else {
System.out.println("重复办理身份证,获取旧号码号码");
}
return instance;
}
private void setIdentityCardNo(String no) {
this.no = no;
}
public String getIdentityCardNo() {
return no;
}
}
// 测试类
public class Client {
public static void main(String[] args) {
IdentityCardNo no1, no2;
no1 = IdentityCardNo.getInstance();
no2 = IdentityCardNo.getInstance();
System.out.println("no1 == no2 ? " + (no1 == no2));
String str1, str2;
str1 = no1.getIdentityCardNo();
str2 = no1.getIdentityCardNo();
System.out.println("第一次号码:" + str1);
System.out.println("第二次号码:" + str2);
System.out.println("内容是否相等:" + str.equalsIgnoreCase(str2));
System.out.println("是否是相同对象:" + (str1 == str2));
}
}
扩展
饿汉式单例
饿汉式单例是在Java语言中实现起来最为方便的单例类,饿汉式单例类结构图如下所示:
在这个类被加载时,静态变量instance会被初始化,此时类的私有构造函数会被调用,单例类的唯一实例将被创建,懒汉式单例
public class LazySingleton {
private static LazySingleton instance = null;
private LazySingleton()
{ }
synchronized public static LazySingleton getInstance() {
if (instance == null)
instance = new LazySingleton();
return instance;
}
}
该懒汉式单例类实现静态工厂方法时使用了同步化机制,以处理多线程环境。
饿汉式单例类在自己被加载时就将自己实例化。单从资源利用效率角度讲,这个比懒汉式单例类稍差些。从速度和反应时间简单来讲,则比懒汉式单例类稍好些。然而,懒汉式单例类在实例化时,必须处理好多个线程同时首次引用此类时的访问限制问题,特别是当单例类作为资源管理器,在实例化时必然涉及资源初始化,而资源初始化很有可能耗费大量时间,这就意味着多个线程同时首次引用此类的几率变得较大,需要通过同步化机制进行控制。