Design Patterns教程-Java 中的单例设计模式
单例模式表示“定义一个类,该类只有一个实例,并提供一个全局访问点。”
换句话说,一个类必须确保只创建一个实例,并且该实例可以被所有其他类使用。
单例设计模式有两种形式
- 早期实例化: 在加载时创建实例。
- 懒惰实例化: 在需要时创建实例。
单例设计模式的优点
- 节省内存,因为对象不会在每次请求时创建。单个实例被反复使用。
单例设计模式的使用场景
- 单例模式主要用于多线程和数据库应用程序。它用于日志记录、缓存、线程池、配置设置等。
单例设计模式的 UML
如何创建单例设计模式?
要创建单例类,我们需要有类的静态成员、私有构造函数和静态工厂方法。
- 静态成员: 由于静态特性,它只占用一次内存,它包含单例类的实例。
- 私有构造函数: 它将防止从类外部实例化单例类。
- 静态工厂方法: 这提供了单例对象的全局访问点,并返回实例给调用者。
了解单例模式的早期实例化
在这种情况下,我们在声明静态数据成员时创建类的实例,因此在类加载时创建类的实例。
让我们看看使用早期实例化的单例设计模式示例。
文件:A.java
class A {
private static A obj = new A(); // 早期实例将在加载时创建
private A() {}
public static A getA() {
return obj;
}
public void doSomething() {
// 编写你的代码
}
}
了解单例模式的懒惰实例化
在这种情况下,我们在同步方法或同步块中创建类的实例,因此在需要时创建类的实例。
让我们看看使用懒惰实例化的单例设计模式的简单示例。
文件:A.java
class A {
private static A obj;
private A() {}
public static A getA() {
if (obj == null) {
synchronized (A.class) {
if (obj == null) {
obj = new A(); // 实例将在请求时创建
}
}
}
return obj;
}
public void doSomething() {
// 编写你的代码
}
}
类加载器在单例模式中的重要性
如果单例类被两个类加载器加载,将创建单例类的两个实例,每个类加载器一个实例。
序列化在单例模式中的重要性
如果单例类是可序列化的,你可以序列化单例实例。一旦序列化,你可以反序列化它,但它不会返回单例对象。
要解决这个问题,你需要覆盖 readResolve() 方法,它强制单例。它在对象反序列化后立即调用。它返回单例对象。
public class A implements Serializable {
// 你的单例代码
protected Object readResolve() {
return getA();
}
}
了解单例模式的实际示例
- 我们将创建一个 JDBCSingleton 类。这个 JDBCSingleton 类包含私有的构造函数和自身的私有静态实例 jdbc。
- JDBCSingleton 类提供了一个静态方法来获取其静态实例给外部世界。现在,JDBCSingletonDemo 类将使用 JDBCSingleton 类获取 JDBCSingleton 对象。
假设: 你已经在 MySQL 数据库中创建了一个名为 userdata 的表,该表有三个字段 uid, uname 和 upassword。数据库名称是 ashwinirajput,用户名是 root,密码是 ashwini。
文件:JDBCSingleton.java
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
class JDBCSingleton {
// 第一步
// 创建一个 JDBCSingleton 类
// 静态成员仅持有 JDBCSingleton 类的一个实例
private static JDBCSingleton jdbc;
// JDBCSingleton 防止从任何其他类实例化
private JDBCSingleton() { }
// 现在我们提供全局访问点
public static JDBCSingleton getInstance() {
if (jdbc == null) {
jdbc = new JDBCSingleton();
}
return jdbc;
}
// 从插入、查看等方法中获取连接
private static Connection getConnection() throws ClassNotFoundException, SQLException {
Connection con = null;
Class.forName("com.mysql.jdbc.Driver");
con = DriverManager.getConnection("jdbc:mysql://localhost:3306/ashwanirajput", "root", "ashwani");
return con;
}
// 向数据库插入记录
public int insert(String name, String pass) throws SQLException {
Connection c = null;
PreparedStatement ps = null;
int recordCounter = 0;
try {
c = this.getConnection();
ps = c.prepareStatement("insert into userdata(uname,upassword)values(?,?)");
ps.setString(1, name);
ps.setString(2, pass);
recordCounter = ps.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (ps != null) {
ps.close();
}
if (c != null) {
c.close();
}
}
return recordCounter;
}
// 从数据库查看数据
public void view(String name) throws SQLException {
Connection con = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
con = this.getConnection();
ps = con.prepareStatement("select * from userdata where uname=?");
ps.setString(1, name);
rs = ps.executeQuery();
while (rs.next()) {
System.out.println("Name= " + rs.getString(2) + "\t" + "Password= " + rs.getString(3));
}
} catch (Exception e) {
System.out.println(e);
} finally {
if (rs != null) {
rs.close();
}
if (ps != null) {
ps.close();
}
if (con != null) {
con.close();
}
}
}
// 更新给定用户名的密码
public int update(String name, String password) throws SQLException {
Connection c = null;
PreparedStatement ps = null;
int recordCounter = 0;
try {
c = this.getConnection();
ps = c.prepareStatement(" update userdata set upassword=? where uname='" + name + "' ");
ps.setString(1, password);
recordCounter = ps.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (ps != null) {
ps.close();
}
if (c != null) {
c.close();
}
}
return recordCounter;
}
// 从数据库中删除数据
public int delete(int userid) throws SQLException {
Connection c = null;
PreparedStatement ps = null;
int recordCounter = 0;
try {
c = this.getConnection();
ps = c.prepareStatement(" delete from userdata where uid='" + userid + "' ");
recordCounter = ps.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (ps != null) {
ps.close();
}
if (c != null) {
c.close();
}
}
return recordCounter;
}
} // JDBCSingleton 类结束
文件:JDBCSingletonDemo.java
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
class JDBCSingletonDemo {
static int count = 1;
static int choice;
public static void main(String[] args) throws IOException {
JDBCSingleton jdbc = JDBCSingleton.getInstance();
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
do {
System.out.println("数据库操作");
System.out.println(" --------------------- ");
System.out.println(" 1. 插入 ");
System.out.println(" 2. 查看 ");
System.out.println(" 3. 删除 ");
System.out.println(" 4. 更新 ");
System.out.println(" 5. 退出 ");
System.out.print("\n");
System.out.print("请输入你想在数据库中执行的操作: ");
choice = Integer.parseInt(br.readLine());
switch (choice) {
case 1: {
System.out.print("输入要插入数据库的用户名: ");
String username = br.readLine();
System.out.print("输入要插入数据库的密码: ");
String password = br.readLine();
try {
int i = jdbc.insert(username, password);
if (i > 0) {
System.out.println((count++) + " 数据插入成功");
} else {
System.out.println("数据未插入");
}
} catch (Exception e) {
System.out.println(e);
}
System.out.println("按 Enter 键继续...");
System.in.read();
} // case 1 结束
break;
case 2: {
System.out.print("输入用户名: ");
String username = br.readLine();
try {
jdbc.view(username);
} catch (Exception e) {
System.out.println(e);
}
System.out.println("按 Enter 键继续...");
System.in.read();
} // case 2 结束
break;
case 3: {
System.out.print("输入要删除的用户ID: ");
int userid = Integer.parseInt(br.readLine());
try {
int i = jdbc.delete(userid);
if (i > 0) {
System.out.println((count++) + " 数据删除成功");
} else {
System.out.println("数据未删除");
}
} catch (Exception e) {
System.out.println(e);
}
System.out.println("按 Enter 键继续...");
System.in.read();
} // case 3 结束
break;
case 4: {
System.out.print("输入要更新的用户名: ");
String username = br.readLine();
System.out.print("输入新密码: ");
String password = br.readLine();
try {
int i = jdbc.update(username, password);
if (i > 0) {
System.out.println((count++) + " 数据更新成功");
}
} catch (Exception e) {
System.out.println(e);
}
System.out.println("按 Enter 键继续...");
System.in.read();
} // case 4 结束
break;
default:
return;
}
} while (choice != 5);
}
}