一.模式定义
单例模式是日常开发中用到最多的一种设计模式。
Ensure a class has only one instance and provide a global point of access to it.
单例模式可以确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例,
二.模式要素
单例Singleton
三.举例说明
一个典型的例子就是居民身份证的例子。每个人在出生后都会分配一张身份证,身份证上的号码是唯一的,以后即使迁转户口,证件丢失,新办理的身份证依旧还是使用之前的号码。
四.模式实例
1.懒汉模式
/**
* @program: DesignModes
* @description: Main
* @author: Lei Dong
* @create: 2018-09-20 22:26
**/
public class Main {
public static void main(String[] args) {
Singleton1 singleton1 = Singleton1.getInstance();
singleton1.showInfo();
}
}
/**
* 懒汉
*/
class Singleton1 {
private static Singleton1 instance;
private Singleton1() {
}
public static Singleton1 getInstance() {
if(instance == null) {
instance = new Singleton1();
}
return instance;
}
void showInfo() {
System.out.println("我是懒汉模式");
}
}
运行结果
2.饿汉模式
/**
* @program: DesignModes
* @description: Main
* @author: Lei Dong
* @create: 2018-09-20 22:26
**/
public class Main {
public static void main(String[] args) {
Singleton2 singleton1 = Singleton2.getInstance();
singleton1.showInfo();
}
}
/**
* 饿汉
*/
class Singleton2 {
private static Singleton2 instance = new Singleton2();
private Singleton2() {
}
public static Singleton2 getInstance() {
return instance;
}
void showInfo() {
System.out.println("我是饿汉模式");
}
}
运行结果:
3.双检锁模式
/**
* @program: DesignModes
* @description: Main
* @author: Lei Dong
* @create: 2018-09-20 22:26
**/
public class Main {
public static void main(String[] args) {
Singleton3 singleton3 = Singleton3.getInstance();
singleton3.showInfo();
}
}
/**
* 双检锁
*/
class Singleton3 {
private static volatile Singleton3 instance;
private Singleton3() {
}
public static Singleton3 getInstance() {
if (instance == null) {
synchronized (Singleton3.class) {
if (instance == null) {
instance = new Singleton3();
}
}
}
return instance;
}
void showInfo() {
System.out.println("我是双检锁模式");
}
}
运行结果:
4.静态内部类模式
/**
* @program: DesignModes
* @description: Main
* @author: Lei Dong
* @create: 2018-09-20 22:26
**/
public class Main {
public static void main(String[] args) {
Singleton4 singleton4 = Singleton4.getInstance();
singleton4.showInfo();
}
}
/**
* 静态内部类
*/
class Singleton4 {
private Singleton4() {
}
private static class Holder {
private static final Singleton4 INSTANCE = new Singleton4();
}
public static Singleton4 getInstance() {
return Holder.INSTANCE;
}
void showInfo() {
System.out.println("我是静态内部类模式");
}
}
运行结果:
五.总结
1.单例模式的优点
(1) 提供了对唯一实例的受控访问。因为单例类封装了它的唯一实例,所以它可以严格控制客户怎样以及何时访问它,并为设计及开发团队提供了共享的概念。
(2)由于在系统内存中只存在一个对象,因此可以节约系统资源,对于一些需要频繁创建和销毁的对象,单例模式无疑可以提高系统的性能。
(3)允许可变数目的实例。我们可以基于单例模式进行扩展,使用与单例控制相似的方法来获得指定个数的对象实例。
2.单例模式的缺点
(1) 由于单例模式中没有抽象层,因此单例类的扩展有很大的困难。
(2)单例类的职责过重,在一定程度上违背了“单一职责原则”。因为单例类既充当了工厂角色,提供了工厂方法,同时又充当了产品角色,包含一些业务方法,将产品的创建和产品的本身的功能融合到一起。
(3)滥用单例将带来一些负面问题,如为了节省资源将数据库连接池对象设计为单例类,可能会导致共享连接池对象的程序过多而出现连接池溢出;现在很多面向对象语言(如Java、C#)的运行环境都提供了自动垃圾回收的技术,因此,如果实例化的对象长时间不被利用,系统会认为它是垃圾,会自动销毁并回收资源,下次利用时又将重新实例化,这将导致对象状态的丢失。
2.单例模式的适用环境
在以下情况下可以使用单例模式:
(1) 系统只需要一个实例对象,如系统要求提供一个唯一的序列号生成器,或者需要考虑资源消耗太大而只允许创建一个对象。
(2)客户调用类的单个实例只允许使用一个公共访问点,除了该公共访问点,不能通过其他途径访问该实例。
(3)在一个系统中要求一个类只有一个实例时才应当使用单例模式。反过来,如果一个类可以有几个实例共存,就需要对单例模式进行改进,使之成为多例模式。