设计模式——单例模式

单例模式 (Singleton Pattern)

什么是单例模式?

单例模式是设计模式中最简单、最基础的一种模式。它的核心思想是:确保一个类在整个程序运行期间只有一个实例,并提供一个全局访问点来访问这个实例。

生活中的例子

想象一下:

  • 数据库连接池:整个应用程序只需要一个连接池来管理数据库连接
  • 配置管理器:应用程序的配置信息只需要加载一次,全局共享
  • 日志记录器:通常只需要一个日志记录器来统一管理日志输出
  • Windows任务管理器:无论你打开多少次任务管理器,都只会有一个窗口

为什么需要单例模式?

  1. 节省资源:避免重复创建对象,减少内存和CPU开销
  2. 数据一致性:确保所有地方访问的都是同一个对象,数据保持一致
  3. 便于控制:可以统一管理对象的创建和销毁

单例模式的实现要点

  1. 私有构造方法 :防止外部通过new关键字创建对象
  2. 私有静态实例:在类内部保存唯一的实例
  3. 公共静态访问方法 :提供全局访问点,如getInstance()

代码示例

单例模式实现:数据库连接池

使用静态内部类方式实现,线程安全且延迟加载。这是单例模式最推荐的实现方式,因为:

  1. 线程安全:由JVM保证类的加载机制
  2. 延迟加载:只有在调用getInstance()时才会加载Holder类
  3. 代码简洁:不需要同步代码块
java 复制代码
/**
 * 单例模式实现:数据库连接池
 * 使用静态内部类方式实现,线程安全且延迟加载
 * 
 * 这是单例模式最推荐的实现方式,因为:
 * 1. 线程安全:由JVM保证类的加载机制
 * 2. 延迟加载:只有在调用getInstance()时才会加载Holder类
 * 3. 代码简洁:不需要同步代码块
 */
public class DatabaseConnection {
    
    // 私有构造方法,防止外部通过new创建实例
    private DatabaseConnection() {
        System.out.println("数据库连接池初始化...");
        // 模拟初始化操作
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("数据库连接池初始化完成");
    }
    
    /**
     * 静态内部类,负责持有单例实例
     * 只有在第一次调用getInstance()时,JVM才会加载Holder类并初始化INSTANCE
     */
    private static class Holder {
        private static final DatabaseConnection INSTANCE = new DatabaseConnection();
    }
    
    /**
     * 获取单例实例的公共方法
     * @return 数据库连接池的唯一实例
     */
    public static DatabaseConnection getInstance() {
        return Holder.INSTANCE;
    }
    
    /**
     * 模拟数据库查询操作
     */
    public void query(String sql) {
        System.out.println("执行SQL查询: " + sql);
    }
    
    /**
     * 模拟数据库插入操作
     */
    public void insert(String sql) {
        System.out.println("执行SQL插入: " + sql);
    }
    
    /**
     * 模拟数据库更新操作
     */
    public void update(String sql) {
        System.out.println("执行SQL更新: " + sql);
    }
    
    /**
     * 模拟数据库删除操作
     */
    public void delete(String sql) {
        System.out.println("执行SQL删除: " + sql);
    }
}

使用单例

java 复制代码
/**
 * 单例模式测试类
 * 演示单例模式如何确保只有一个实例
 */
public class SingletonTest {
    
    public static void main(String[] args) {
        System.out.println("=== 单例模式测试 ===\n");
        
        // 获取第一个实例
        DatabaseConnection connection1 = DatabaseConnection.getInstance();
        connection1.query("SELECT * FROM users");
        
        System.out.println();
        
        // 获取第二个实例
        DatabaseConnection connection2 = DatabaseConnection.getInstance();
        connection2.insert("INSERT INTO users VALUES (1, '张三')");
        
        System.out.println();
        
        // 获取第三个实例
        DatabaseConnection connection3 = DatabaseConnection.getInstance();
        connection3.update("UPDATE users SET name='李四' WHERE id=1");
        
        System.out.println("\n=== 验证是否为同一个实例 ===");
        System.out.println("connection1 == connection2: " + (connection1 == connection2));
        System.out.println("connection2 == connection3: " + (connection2 == connection3));
        System.out.println("connection1 == connection3: " + (connection1 == connection3));
        
        System.out.println("\n=== 验证hashCode是否相同 ===");
        System.out.println("connection1.hashCode(): " + connection1.hashCode());
        System.out.println("connection2.hashCode(): " + connection2.hashCode());
        System.out.println("connection3.hashCode(): " + connection3.hashCode());
    }
}

常见的实现方式

1. 饿汉式(立即加载)

java 复制代码
public class Singleton {
    private static final Singleton instance = new Singleton();
    
    private Singleton() {}
    
    public static Singleton getInstance() {
        return instance;
    }
}

优点 :线程安全,简单
缺点:类加载时就创建实例,可能造成资源浪费

2. 懒汉式(延迟加载)

java 复制代码
public class Singleton {
    private static Singleton instance;
    
    private Singleton() {}
    
    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

优点 :延迟加载,节省资源
缺点:线程不安全

3. 双重检查锁(推荐)

java 复制代码
public class Singleton {
    private static volatile Singleton instance;
    
    private Singleton() {}
    
    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

优点 :线程安全,延迟加载,性能好
缺点:代码稍复杂

4. 静态内部类(推荐)

java 复制代码
public class Singleton {
    private Singleton() {}
    
    private static class Holder {
        private static final Singleton INSTANCE = new Singleton();
    }
    
    public static Singleton getInstance() {
        return Holder.INSTANCE;
    }
}

优点 :线程安全,延迟加载,代码简洁
缺点:无

适用场景

  • 需要频繁创建和销毁的对象
  • 创建对象耗时或耗费资源较多
  • 工具类对象
  • 频繁访问数据库或文件的对象
  • 全局共享的配置信息

使用建议

  • 优先使用静态内部类方式,它是最优雅的实现
  • 如果需要支持序列化,要注意防止反序列化创建新对象
  • 如果需要支持反射,要防止反射创建新对象
  • 在Android开发中,可以使用Application类作为单例

注意事项

⚠️ 单例模式虽然简单,但不要滥用!过度使用单例会导致:

  • 代码难以测试(全局状态难以隔离)
  • 隐藏类之间的依赖关系
  • 违反单一职责原则(单例类承担过多责任)
相关推荐
dxnb222 小时前
Datawhale26年1月组队学习:Agentic AI+Task2反思设计模式
学习·设计模式
老蒋每日coding2 小时前
AI智能体设计模式系列(八)—— 记忆管理模式
人工智能·设计模式·golang
Mr YiRan2 小时前
重学设计模式之拦截器和责任链
设计模式
小码过河.2 小时前
设计模式——享元模式
java·设计模式·享元模式
Geoking.16 小时前
【设计模式】中介者模式(Mediator)详解
java·设计模式·中介者模式
Yuzhiyuxia18 小时前
【设计模式】设计模式学习总结
学习·设计模式
小屁猪qAq19 小时前
设计模式的基石
开发语言·c++·设计模式
一条闲鱼_mytube19 小时前
智能体设计模式(一):提示链、路由与并行化
人工智能·设计模式
Yu_Lijing21 小时前
基于C++的《Head First设计模式》笔记——模版方法模式
笔记·设计模式