单例模式
本课属于 Coddy Java 学习旅程的“面向对象编程”单元。第 65 课,共 87 课。
单例模式是一种创建型设计模式,可确保一个类在整个应用程序中只有一个实例,同时提供全局访问该实例的入口。这适用于需要共享的资源,例如配置管理器、连接池或日志服务。
这种模式通过将构造函数设为私有,阻止直接实例化。取而代之的是,通过静态方法控制对唯一实例的访问:
public class DatabaseConnection {
private static DatabaseConnection instance;
// 私有构造方法防止直接创建实例
private DatabaseConnection() {
System.out.println("Connection created");
}
// 全局访问入口
public static DatabaseConnection getInstance() {
if (instance == null) {
instance = new DatabaseConnection();
}
return instance;
}
public void query(String sql) {
System.out.println("Executing: " + sql);
}
}每次调用 getInstance() 都会返回同一个对象。只有在首次请求时才会创建该实例。这称为延迟初始化:
DatabaseConnection db1 = DatabaseConnection.getInstance();
DatabaseConnection db2 = DatabaseConnection.getInstance();
System.out.println(db1 == db2); // true,指向同一个实例单例的关键组成部分包括:一个保存实例的 private static 字段、一个 private 构造函数,以及一个返回该实例的 public static 方法。这种组合可以确保,无论你请求对象多少次,得到的始终都是同一个对象。
挑战
简单让我们使用单例模式为应用构建一个配置管理器!你的配置管理器会确保应用的所有部分共享相同的设置,无论它们请求访问多少次。
你会把代码分到两个文件中:
AppConfig.java:创建一个管理应用配置设置的单例类。你的AppConfig应包含:一个用于保存唯一实例的私有静态字段。
一个名为
appName的私有 String 字段,以及一个名为maxUsers的私有 int 字段。一个私有构造函数,将
appName初始化为"MyApplication",将maxUsers初始化为"100",然后输出AppConfig initialized。一个公有静态
getInstance()方法,仅当实例尚不存在时才创建它(延迟初始化),然后返回该实例。一个用于更新应用名称的
setAppName(String name)方法。一个用于更新最大用户数的
setMaxUsers(int max)方法。一个用于输出
App: [appName], Max Users: [maxUsers]的displaySettings()方法。Main.java:演示你的单例能否正常工作!你会收到两个输入:新的应用名称(String)和新的最大用户数(整数)。首先,获取一个
AppConfig实例,并将它存入名为config1的变量。调用displaySettings()显示默认值。然后,通过在
config1上调用setAppName和setMaxUsers,使用输入值更新设置。再获取一个实例,并将它存入
config2。在config2上调用displaySettings(),证明它反映了通过config1所做的更改。最后,通过比较
config1 == config2,输出两个引用是否指向同一个对象:Same instance: [true/false]。
你会按顺序收到两个输入:新的应用名称(String)和新的最大用户数(整数)。
这个挑战展示了单例模式的核心优势:无论你请求获取配置多少次,得到的始终是同一个具有共享状态的实例!
亲手试试
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// 读取输入
String newAppName = scanner.nextLine();
int newMaxUsers = scanner.nextInt();
// TODO: 获取 AppConfig 的第一个实例,并存入 config1
// TODO: 在 config1 上调用 displaySettings(),显示默认值
// TODO: 在 config1 上使用 setAppName 和 setMaxUsers 更新设置
// TODO: 获取另一个实例,并存入 config2
// TODO: 在 config2 上调用 displaySettings(),证明更改是共享的
// TODO: 输出两个引用是否指向同一个对象:
// 使用 config1 == config2 输出 "Same instance: [true/false]"
}
}
这节课包含一个小测验。开始学习即可作答,并记录你的进度。
面向对象编程中的所有课
自己练习: Java 在线编译器