
Singleton模式——只有一个实例(单例模式)
Singleton模式
当程序中需要类“只能创建一个实例”时,如表示字符串的 java.lang.String
类的实例与字符串,像这样的模式称为 Singleton模式(单例模式)
单例模式主要特点:
- 想确保任何情况下都绝对只有1个实例
- 想在程序上表现出“只存在一个实例”
示例程序
类的一览表:
名字 | 说明 |
---|---|
Singleton | 只存在一个实例的类 |
Main | 测试程序行为的类 |
示例程序的类图:
Singleton类
Singleton类只会生成一个实例。Singleton类定义了 static 字段(类的成员变量)singleton,并将其初始化为 Singleton 类的实例。初始化为Sigleton类的实例。初始化行为仅在该类被加载时进行一次。
public class Singleton {
private static final Singleton singleton = new Singleton();
private Singleton() {
System.out.println(" 生成了一个实例。 ");
}
public static Singleton getInstance() {
return singleton;
}
}
- Singleton类的构造函数是 private 的,这是为了禁止从 Singleton 类外部调用构造函数
Main类
public class Main {
public static void main(String[] args) {
System.out.println("Start.");
Singleton obj1 = Singleton.getInstance();
Singleton obj2 = Singleton.getInstance();
if (obj1 == obj2) {
System.out.println("obj1与obj2是相同的实例");
} else {
System.out.println("obj1与obj2是不同的实例");
}
System.out.println("End.");
}
}
运行结果如下:
Start.
生成了一个实例。
obj1与obj2是相同的实例
End.
Singleton模式中的登场角色
Singleton
在 Singleton 模式中,只有 Singleton 这一个角色。Singleton角色有一个返回唯一示例 static 方法。该方法总是会返回同一个实例。
Singleton 模式类图
:
拓展思路
为什么必须设置限制
当存在多个实例中,实例之间若是互相影响,可能产生意想不到的bug。
如果确保只有一个实例,那么就不需要担心实例间的影响了。
何时生成这个唯一的实例
当程序运行后,第一次调用 getInstance()
时。也是在这个时候,static 字段 singleton 被初始化,生成了唯一的一个实例。
练习题
习题1
在下面的TicketMaker类(代码清单5-3)中,每次调用getNextTicketNumber方法都会返回1000,1001,1002...的数列。我们可以用它生成票的编号或是其他序列号。在现在该类的实现方式下,我们可以生成多个该类的实例。请修改代码,运用Singleton模式确保只能生成一个该类的实例。
TicketMaker.java
:
public class TicketMaker {
private int ticket = 1000;
public int getNextTicketNumber() {
return ticket++;
}
}
使用单例模式修改:
public class TicketMaker {
private static final TicketMaker ticketMaker = new TicketMaker();
private int ticket = 1000;
public int getNextTicketNumber() {
return ticket++;
}
public static TicketMaker getInstance() {
return ticketMaker;
}
}
没使用示例的话,new出来的对象都不是同一个,因此getNextTicketNumber都会返回 1000
,但是使用单例就可以累加。
习题2
请编写Triple类,实现最多只能生成3个Trip1e类的实例,实例编号分别为0,1,2且可以通过getInstance(int id)来获取该编号对应的实例(在第10章中也出现了这样的类)。
public class Triple {
private static final Triple[] triples = new Triple[]{
new Triple(0),
new Triple(1),
new Triple(2)
};
private int id;
private Triple() {
}
private Triple(int id) {
System.out.println("The instance " + id + " is created.");
this.id = id;
}
public static Triple getInstance(int id) {
return triples[id];
}
@Override
public String toString() {
return "Triple id=" + id;
}
}
Main
:
public class Main {
public static void main(String[] args) {
for (int i = 0; i < 9; i++) {
Triple triple = Triple.getInstance(i % 3);
System.out.println(i + ":" + triple);
}
System.out.println("End.");
}
}
- 感谢你赐予我前进的力量