5Head First Design Patterns(第2版)

单例模式

唯一实例

单例模式线程安全双重检查锁枚举单例

🎯 AI 时代的学习建议:不要只读理论。理解这一章的设计动机(为什么需要这个概念?)和边界条件(什么情况下会失效?)。当 AI 生成的代码涉及这些概念时,你能判断它是否用对了场景。AI 能帮你总结内容,但无法替代你亲手阅读、思考、建立直觉的过程。

第5章:单例模式(Singleton Pattern)

一、导读

1.1 本章学习目标

第5章讲解单例模式——确保一个类只有一个实例,并提供一个全局访问点。

1.2 为什么第五章如此重要

单例模式看似简单,实则有很多陷阱:线程安全、序列化、延迟初始化等问题需要仔细处理。

1.3 核心问题引导

单例模式有哪些实现方式?

如何保证线程安全?

双重检查锁的原理是什么?

枚举单例为什么是最佳方式?


二、核心概念详解

5.1 经典实现

java
// 懒汉式(线程不安全)
public class Singleton {
    private static Singleton instance;
    private Singleton() {}
    
    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

5.2 线程安全实现

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;
    }
}

// 枚举方式(推荐)
public enum Singleton {
    INSTANCE;
    
    public void doSomething() { }
}

5.3 单例的问题

单例的反面观点:
- 违反单一职责原则
- 隐藏依赖关系
- 难以测试
- 全局状态

替代方案:
- 依赖注入
- 使用 Spring 的 Bean(默认单例)

三、实战案例

3.1 配置管理器

java
public class ConfigManager {
    private Map<String, String> config = new HashMap<>();
    
    private ConfigManager() {
        // 加载配置
    }
    
    private static class Holder {
        static final ConfigManager INSTANCE = new ConfigManager();
    }
    
    public static ConfigManager getInstance() {
        return Holder.INSTANCE;
    }
    
    public String get(String key) {
        return config.get(key);
    }
}

四、本章小结

单例确保一个类只有一个实例。枚举方式是最佳实现,双重检查锁需要注意 volatile。但单例有争议,依赖注入是更好的替代方案。


五、思考与练习

单例模式有哪些实现方式?

为什么双重检查锁需要 volatile?

枚举单例为什么是线程安全的?

单例有什么缺点?

依赖注入如何替代单例?


5/12单例模式
0%