单例模式

单例模式(Singleton Pattern)是中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。

单例模式是一种创建型设计模式,它确保一个类只有一个实例,并提供了一个全局访问点来访问该实例。

注意:

1、单例类只能有一个实例。
2、单例类必须自己创建自己的唯一实例。
3、单例类必须给所有其他对象提供这一实例。

主要解决

频繁创建和销毁全局使用的类实例的问题。

何时使用

当需要控制实例数目,节省系统资源时。

类图示例

单例模式.png

代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class SingleObject {
private static SingleObject instance = new SingleObject();

private SingleObject() {
}

public static SingleObject getInstance() {
return instance;
}

public void showMessage() {
System.out.println("Hello World");
}
}

public class Singleton {
public static void main(String[] args) {
//不能使用构造函数
//SingleObject s1 = new SingleObject();
SingleObject s1 = SingleObject.getInstance();
s1.showMessage();
}
}

单例模式的几种实现方式

懒汉式(只有使用时才会加载实例),线程不安全

1
2
3
4
5
6
7
8
9
10
class SingleObject {
private static SingleObject instance;
private SingleObject() {}
public static SingleObject getInstance() {
if (instance == null) {
instance = new SingleObje();
}
return instance;
}
}

懒汉式(只有使用时才会加载实例),线程安全

使用加锁的方式

1
2
3
4
5
6
7
8
9
10
class SingleObject {
private static SingleObject instance;
private SingleObject() {}
public static synchronized SingleObject getInstance(){
if(instance == null){
instance = new SingleObject();
}
return instance;
}
}

饿汉式(加载类的时候就实例化)

1
2
3
4
5
6
7
class SingleObject {
private static SingleObject instance = new SingleObject();
private SingleObject() {}
public static SingleObject getInstance() {
return instance;
}
}

双重锁

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class SingleObject {
private static SingleObject instance;
private SingleObject() {}
public static SingleObject getInstance() {
if (instance == null) {
synchronized (SingleObject.class) {
if (instance == null) {
instance = new SingleObject();
}
}
}
return instance;
}
}

模式分析

单例模式的目的是保证一个类仅有一个实例,并提供一个访问它的全局访问点。单例模式包含的角色只有一个就是单例类。单例模式拥有一个私有构造函数,确保用户无法通过new直接实例化。

优点

  1. 节省资源:单例模式通过确保一个类只有一个实例来避免重复创建对象,从而节省了内存和计算资源。这对于需要频繁创建和销毁对象的场景特别有用。
  2. 全局访问:单例模式提供了一个全局访问点来访问该类的实例,这使得在程序的任何地方都可以方便地获取和使用该实例。
  3. 控制实例数量:通过单例模式,可以严格控制一个类在内存中的实例数量,从而避免因为多个实例导致的资源竞争和数据不一致等问题。
  4. 简化管理:由于只有一个实例,因此可以更容易地管理和维护该实例的状态和行为,特别是在需要跟踪和记录实例变化的情况下。

缺点

  1. 单例类的职责过重:如果单例类承担了过多的职责,会导致代码结构复杂,难以维护和扩展。这违反了单一职责原则,即一个类应该只有一个引起它变化的理由。
  2. 线程安全问题:在多线程环境下,如果没有正确实现同步机制,可能会导致多个实例被创建。虽然可以通过加锁等方式来解决这个问题,但会增加代码的复杂性和执行开销。
  3. 难以测试:由于单例类的实例在程序中是唯一的,因此很难对其进行单元测试。这通常需要使用特殊的测试技巧,如依赖注入、模拟(mock)等。
  4. 依赖关系:单例模式可能导致代码之间的紧密依赖关系,特别是当多个类依赖于同一个单例实例时。这种依赖关系会增加代码的耦合度,降低系统的灵活性和可维护性。
  5. 扩展困难:如果需要在程序中引入新的单例类,或者需要修改现有单例类的行为,可能会涉及到大量的代码修改和测试工作。这增加了系统扩展和维护的难度。