【设计模式】A1-单例模式

👉 更多 文章、资料、干货 ,尽在个人主页!点击头像,获取更多~ 📚


我们将深入探讨 Java 设计模式中最为基础也最为重要的一种------单例设计模式。这不仅仅是一个模式,它关乎程序的性能、资源的合理利用以及线程安全的核心原则。

无论你是初学者还是经验丰富的开发者,这篇详尽的指南都将为你提供深入的见解和实用的代码示例。


📚 什么是单例模式?

单例模式属于创建型模式 ,其核心目标是确保一个类在 JVM 中只有一个实例。它提供了一种全局访问点来获取这个唯一的实例,而无需频繁地创建和销毁对象。

🎯 为什么需要单例模式?

  • 资源控制: 某些资源(如数据库连接池、线程池、配置文件读取器)是有限的,创建多个实例会造成资源浪费和冲突。
  • 性能优化: 频繁创建和销毁对象(特别是重量级对象)会带来性能开销。单例可以避免这种开销。
  • 全局状态: 某些场景需要一个全局的、共享的状态管理器,单例是实现这一点的理想选择。

🏗️ 单例模式的结构

单例模式主要包含两个角色:

  • 单例类 (Singleton Class): 负责创建并管理自身的唯一实例。它拥有一个私有的构造方法,防止外部直接实例化。
  • 访问类 (Client Class): 通过单例类提供的公共静态方法来获取其唯一实例。

⚙️ 单例模式的实现方式

单例模式主要有两种实现思路:饿汉式懒汉式。它们的核心区别在于实例化时机。

1️⃣ 饿汉式 (Eager Initialization)

特点:在类加载时就创建实例,线程安全,但可能存在内存浪费。

方式一:静态变量方式

这是最直观的实现方式,实例在类加载时立即创建。

复制代码
/**
 * 饿汉式 - 静态变量方式
 * 优点:写法简单,类加载时就完成了实例化,避免了线程同步问题。
 * 缺点:容易造成内存浪费(无论是否使用,实例都会被创建)。
 */
public class EagerSingleton_StaticVariable {

    // 1. 私有构造方法,防止外部 new
    private EagerSingleton_StaticVariable() {
        System.out.println("EagerSingleton_StaticVariable 构造方法被调用...");
    }

    // 2. 在类加载时就创建好唯一的实例
    private static final EagerSingleton_StaticVariable INSTANCE = new EagerSingleton_StaticVariable();

    // 3. 提供公共静态方法供外部获取实例
    public static EagerSingleton_StaticVariable getInstance() {
        return INSTANCE;
    }
}

// --- 应用场景示例:数据库配置管理器 ---
class DatabaseConfigManager {
    private String url;
    private String username;
    private String password;

    private DatabaseConfigManager() {
        // 从配置文件加载,或从环境变量读取
        this.url = "jdbc:mysql://localhost:3306/mydb";
        this.username = "admin";
        this.password = "secret";
        System.out.println("DatabaseConfigManager 初始化完成,加载配置信息。");
    }

    private static final DatabaseConfigManager INSTANCE = new DatabaseConfigManager();

    public static DatabaseConfigManager getInstance() {
        return INSTANCE;
    }

    public String getUrl() { return url; }
    public String getUsername() { return username; }
    public String getPassword() { return password; }
}

// --- 测试 ---
class EagerTest {
    public static void main(String[] args) {
        // 无论是否调用 getInstance,INSTANCE 都已经创建了
        EagerSingleton_StaticVariable s1 = EagerSingleton_StaticVariable.getInstance();
        EagerSingleton_StaticVariable s2 = EagerSingleton_StaticVariable.getInstance();

        System.out.println("s1 == s2: " + (s1 == s2)); // 输出: true

        // 使用配置管理器
        DatabaseConfigManager config1 = DatabaseConfigManager.getInstance();
        DatabaseConfigManager config2 = DatabaseConfigManager.getInstance();
        System.out.println("Config1 URL: " + config1.getUrl());
        System.out.println("Config1 == Config2: " + (config1 == config2)); // 输出: true
    }
}
方式二:静态代码块方式

与方式一类似,但将实例创建放在了静态代码块中,这在需要进行一些复杂初始化操作时可能有用。

复制代码
/**
 * 饿汉式 - 静态代码块方式
 * 优点:写法简单,类加载时就完成了实例化,避免了线程同步问题。
 *       静态代码块中可以执行更复杂的初始化逻辑。
 * 缺点:同样容易造成内存浪费。
 */
public class EagerSingleton_StaticBlock {

    private EagerSingleton_StaticBlock() {
        System.out.println("EagerSingleton_StaticBlock 构造方法被调用...");
    }

    private static final EagerSingleton_StaticBlock INSTANCE;

    static { // 静态代码块,在类加载时执行一次
        System.out.println("开始在静态代码块中创建实例...");
        INSTANCE = new EagerSingleton_StaticBlock();
        System.out.println("实例创建完成。");
    }

    public static EagerSingleton_StaticBlock getInstance() {
        return INSTANCE;
    }
}

// --- 测试 ---
class EagerBlockTest {
    public static void main(String[] args) {
        EagerSingleton_StaticBlock s1 = EagerSingleton_StaticBlock.getInstance();
        EagerSingleton_StaticBlock s2 = EagerSingleton_StaticBlock.getInstance();
        System.out.println("s1 == s2: " + (s1 == s2)); // 输出: true
    }
}

2️⃣ 懒汉式 (Lazy Initialization)

特点:在首次调用 getInstance() 时才创建实例,节省内存 ,但需要处理线程安全问题。

方式一:线程不安全的懒汉式

这是最基础的懒加载实现,但在多线程环境下是不安全的。

复制代码
/**
 * 懒汉式 - 线程不安全
 * 优点:实现了懒加载,节省内存。
 * 缺点:在多线程环境下,可能会创建多个实例,导致线程安全问题。
 */
public class LazySingleton_Unsafe {

    private LazySingleton_Unsafe() {
        System.out.println("LazySingleton_Unsafe 构造方法被调用...");
    }

    private static LazySingleton_Unsafe instance; // 初始为 null

    public static LazySingleton_Unsafe getInstance() {
        if (instance == null) { // 1. 检查实例是否已存在
            instance = new LazySingleton_Unsafe(); // 2. 如果不存在,则创建
        }
        return instance;
    }
}

// --- 测试线程安全问题 ---
class UnsafeTest {
    public static void main(String[] args) throws InterruptedException {
        Runnable task = () -> {
            LazySingleton_Unsafe singleton = LazySingleton_Unsafe.getInstance();
            System.out.println(Thread.currentThread().getName() + " 获取到的实例: " + singleton);
        };

        Thread t1 = new Thread(task, "Thread-1");
        Thread t2 = new Thread(task, "Thread-2");

        t1.start();
        t2.start();

        t1.join(); // 等待 t1 结束
        t2.join(); // 等待 t2 结束
        // 可能输出两个不同的实例地址,证明线程不安全。
    }
}
方式二:线程安全的懒汉式(同步方法)

通过在 getInstance 方法上加 synchronized 关键字来保证线程安全。

复制代码
/**
 * 懒汉式 - 线程安全(同步方法)
 * 优点:解决了线程安全问题。
 * 缺点:效率低。每次调用 getInstance 都需要获取锁,即使实例已经创建。
 */
public class LazySingleton_SynchronizedMethod {

    private LazySingleton_SynchronizedMethod() {
        System.out.println("LazySingleton_SynchronizedMethod 构造方法被调用...");
    }

    private static LazySingleton_SynchronizedMethod instance;

    // synchronized 关键字确保同一时间只有一个线程可以执行此方法
    public static synchronized LazySingleton_SynchronizedMethod getInstance() {
        if (instance == null) {
            instance = new LazySingleton_SynchronizedMethod();
        }
        return instance;
    }
}

// --- 测试 ---
class SynchronizedMethodTest {
    public static void main(String[] args) throws InterruptedException {
        Runnable task = () -> {
            LazySingleton_SynchronizedMethod singleton = LazySingleton_SynchronizedMethod.getInstance();
            System.out.println(Thread.currentThread().getName() + " 获取到的实例: " + singleton);
        };

        Thread t1 = new Thread(task, "Thread-1");
        Thread t2 = new Thread(task, "Thread-2");

        t1.start();
        t2.start();

        t1.join();
        t2.join();
        // 会输出同一个实例地址,但性能较差。
    }
}
方式三:双重检查锁

这是懒汉式中推荐的高性能实现方式,它结合了懒加载和线程安全,同时避免了同步方法的性能瓶颈。

复制代码
/**
 * 懒汉式 - 双重检查锁 (DCL)
 * 优点:线程安全,性能高,实现了懒加载。
 * 缺点:代码相对复杂,需要理解 volatile 的作用。
 */
public class LazySingleton_DoubleCheckedLocking {

    private LazySingleton_DoubleCheckedLocking() {
        System.out.println("LazySingleton_DoubleCheckedLocking 构造方法被调用...");
    }

    // 1. 使用 volatile 关键字非常重要!
    // 它确保 instance 的写入操作对所有线程立即可见,并禁止 JVM 指令重排序。
    // 如果没有 volatile,在多线程环境下可能发生指令重排序,
    // 导致其他线程拿到一个未完全初始化的对象(例如,对象的内存已分配,但构造函数尚未执行完毕)。
    private static volatile LazySingleton_DoubleCheckedLocking instance;

    public static LazySingleton_DoubleCheckedLocking getInstance() {
        if (instance == null) { // 第一次检查,避免不必要的同步
            synchronized (LazySingleton_DoubleCheckedLocking.class) { // 加锁
                if (instance == null) { // 第二次检查,确保只创建一个实例
                    instance = new LazySingleton_DoubleCheckedLocking();
                }
            } // 释放锁
        }
        return instance;
    }
}

// --- 应用场景示例:日志记录器 ---
class Logger {
    private Logger() {
        System.out.println("Logger 初始化...");
    }

    private static volatile Logger instance;

    public static Logger getInstance() {
        if (instance == null) {
            synchronized (Logger.class) {
                if (instance == null) {
                    instance = new Logger();
                }
            }
        }
        return instance;
    }

    public void log(String message) {
        System.out.println("[" + System.currentTimeMillis() + "] " + message);
    }
}

// --- 测试 ---
class DCLTest {
    public static void main(String[] args) throws InterruptedException {
        Runnable task = () -> {
            LazySingleton_DoubleCheckedLocking singleton = LazySingleton_DoubleCheckedLocking.getInstance();
            System.out.println(Thread.currentThread().getName() + " 获取到的实例: " + singleton);
        };

        Thread t1 = new Thread(task, "Thread-1");
        Thread t2 = new Thread(task, "Thread-2");

        t1.start();
        t2.start();

        t1.join();
        t2.join();
        // 输出同一个实例地址,且性能优于同步方法。

        // 使用日志记录器
        Logger logger1 = Logger.getInstance();
        Logger logger2 = Logger.getInstance();
        logger1.log("Hello from Logger1");
        logger2.log("Hello from Logger2");
        System.out.println("Logger1 == Logger2: " + (logger1 == logger2)); // 输出: true
    }
}
方式四:静态内部类

这是推荐的单例实现方式之一,它利用了 JVM 类加载机制来保证线程安全,同时实现了懒加载,且没有性能损耗。

复制代码
/**
 * 静态内部类方式
 * 优点:线程安全,利用 JVM 类加载机制保证实例唯一性,实现了懒加载,性能高,无锁。
 * 原理:外部类加载时,内部类 SingletonHolder 并不立即加载。
 *       只有当调用 getInstance() 时,才会触发 SingletonHolder 的加载和 INSTANCE 的初始化。
 *       JVM 保证了类加载过程的线程安全。
 */
public class Singleton_StaticInnerClass {

    private Singleton_StaticInnerClass() {
        System.out.println("Singleton_StaticInnerClass 构造方法被调用...");
    }

    // 1. 定义一个静态内部类,内部持有单例实例
    private static class SingletonHolder {
        // 2. 在内部类中创建实例,JVM 保证其只被初始化一次
        private static final Singleton_StaticInnerClass INSTANCE = new Singleton_StaticInnerClass();
    }

    // 3. 提供公共静态方法,返回内部类中创建的实例
    public static Singleton_StaticInnerClass getInstance() {
        return SingletonHolder.INSTANCE;
    }
}

// --- 应用场景示例:缓存管理器 ---
class CacheManager {
    private Map<String, Object> cache = new ConcurrentHashMap<>();

    private CacheManager() {
        System.out.println("CacheManager 初始化...");
    }

    private static class CacheManagerHolder {
        private static final CacheManager INSTANCE = new CacheManager();
    }

    public static CacheManager getInstance() {
        return CacheManagerHolder.INSTANCE;
    }

    public void put(String key, Object value) {
        cache.put(key, value);
    }

    public Object get(String key) {
        return cache.get(key);
    }
}

// --- 测试 ---
class StaticInnerClassTest {
    public static void main(String[] args) throws InterruptedException {
        System.out.println("程序启动,但尚未调用 getInstance...");
        // 此时 Singleton_StaticInnerClass 和其内部类 SingletonHolder 都未被加载

        Runnable task = () -> {
            Singleton_StaticInnerClass singleton = Singleton_StaticInnerClass.getInstance();
            System.out.println(Thread.currentThread().getName() + " 获取到的实例: " + singleton);
        };

        Thread t1 = new Thread(task, "Thread-1");
        Thread t2 = new Thread(task, "Thread-2");

        t1.start();
        t2.start();

        t1.join();
        t2.join();
        // 输出同一个实例地址,且只在第一次调用时创建。

        // 使用缓存管理器
        CacheManager cache1 = CacheManager.getInstance();
        CacheManager cache2 = CacheManager.getInstance();
        cache1.put("key1", "value1");
        System.out.println("Cached Value: " + cache2.get("key1")); // "value1"
        System.out.println("Cache1 == Cache2: " + (cache1 == cache2)); // 输出: true
    }
}
方式五:枚举 (Enum)

这是最推荐的单例实现方式。它天然支持线程安全,防止反射和序列化破坏单例。

复制代码
/**
 * 枚举方式
 * 优点:实现简单,线程安全,天然防止反射和序列化破坏。
 * 原理:枚举实例在类加载时就被创建(饿汉式),并且 JVM 保证了其唯一性。
 *       枚举的特殊性质使得它无法被反射创建新实例,也无法被序列化破坏。
 */
public enum Singleton_Enum {
    INSTANCE; // 唯一的实例

    // 可以定义方法
    public void doSomething() {
        System.out.println("Singleton_Enum is doing something...");
    }
}

// --- 应用场景示例:系统配置 ---
enum SystemConfig {
    INSTANCE;

    private String version = "1.0.0";
    private boolean debugMode = false;

    public String getVersion() { return version; }
    public boolean isDebugMode() { return debugMode; }
    public void setDebugMode(boolean debugMode) { this.debugMode = debugMode; }
}

// --- 测试 ---
class EnumTest {
    public static void main(String[] args) {
        Singleton_Enum s1 = Singleton_Enum.INSTANCE;
        Singleton_Enum s2 = Singleton_Enum.INSTANCE;
        System.out.println("s1 == s2: " + (s1 == s2)); // 输出: true
        s1.doSomething(); // 调用方法

        SystemConfig config = SystemConfig.INSTANCE;
        System.out.println("Version: " + config.getVersion());
        System.out.println("Debug Mode: " + config.isDebugMode());
    }
}

💥 破坏单例模式的两种方式

尽管我们精心设计了单例,但仍有可能被破坏。

1. 序列化与反序列化

当一个单例对象被序列化到文件,再从文件反序列化回来时,会创建一个新的对象,从而破坏单例。

复制代码
import java.io.*;

// 一个实现了序列化的单例类(例如使用静态内部类方式)
class SingletonWithSerialization implements Serializable {
    private SingletonWithSerialization() {
        System.out.println("SingletonWithSerialization 构造方法被调用...");
    }

    private static class SingletonHolder {
        private static final SingletonWithSerialization INSTANCE = new SingletonWithSerialization();
    }

    public static SingletonWithSerialization getInstance() {
        return SingletonHolder.INSTANCE;
    }
}

// --- 测试破坏 ---
class SerializationBreakTest {
    public static void main(String[] args) throws Exception {
        SingletonWithSerialization original = SingletonWithSerialization.getInstance();

        // 1. 序列化到文件
        String filename = "singleton.ser";
        try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(filename))) {
            out.writeObject(original);
        }

        // 2. 从文件反序列化
        SingletonWithSerialization deserialized;
        try (ObjectInputStream in = new ObjectInputStream(new FileInputStream(filename))) {
            deserialized = (SingletonWithSerialization) in.readObject();
        }

        System.out.println("Original == Deserialized: " + (original == deserialized)); // 输出: false
        System.out.println("Original: " + original);
        System.out.println("Deserialized: " + deserialized);
        // 结果证明,反序列化创建了一个新对象,破坏了单例。
    }
}

解决方案: 在单例类中添加 readResolve() 方法。

复制代码
class SingletonWithSerializationFixed implements Serializable {
    private SingletonWithSerializationFixed() {
        System.out.println("SingletonWithSerializationFixed 构造方法被调用...");
    }

    private static class SingletonHolder {
        private static final SingletonWithSerializationFixed INSTANCE = new SingletonWithSerializationFixed();
    }

    public static SingletonWithSerializationFixed getInstance() {
        return SingletonHolder.INSTANCE;
    }

    // 3. 添加 readResolve 方法来防止序列化破坏
    private Object readResolve() throws ObjectStreamException {
        // 当 JVM 从流中读取对象时,会调用此方法,并返回此方法的返回值
        // 而不是新建一个对象。这样就保证了单例。
        return SingletonHolder.INSTANCE;
    }
}

// --- 测试修复 ---
class SerializationFixTest {
    public static void main(String[] args) throws Exception {
        SingletonWithSerializationFixed original = SingletonWithSerializationFixed.getInstance();

        String filename = "singleton_fixed.ser";
        try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(filename))) {
            out.writeObject(original);
        }

        SingletonWithSerializationFixed deserialized;
        try (ObjectInputStream in = new ObjectInputStream(new FileInputStream(filename))) {
            deserialized = (SingletonWithSerializationFixed) in.readObject();
        }

        System.out.println("Original == Deserialized (Fixed): " + (original == deserialized)); // 输出: true
    }
}

2. 反射 (Reflection)

通过反射可以强制访问私有构造方法,从而创建新的实例。

复制代码
import java.lang.reflect.Constructor;

// 一个线程安全的懒汉式单例
class SingletonWithReflection {
    private SingletonWithReflection() {
        System.out.println("SingletonWithReflection 构造方法被调用...");
    }

    private static volatile SingletonWithReflection instance;

    public static SingletonWithReflection getInstance() {
        if (instance == null) {
            synchronized (SingletonWithReflection.class) {
                if (instance == null) {
                    instance = new SingletonWithReflection();
                }
            }
        }
        return instance;
    }
}

// --- 测试破坏 ---
class ReflectionBreakTest {
    public static void main(String[] args) throws Exception {
        SingletonWithReflection s1 = SingletonWithReflection.getInstance();

        // 1. 获取类的 Class 对象
        Class<?> clazz = SingletonWithReflection.class;

        // 2. 获取私有构造方法
        Constructor<?> constructor = clazz.getDeclaredConstructor();

        // 3. 设置可访问(绕过私有访问限制)
        constructor.setAccessible(true);

        // 4. 通过反射创建新实例
        SingletonWithReflection s2 = (SingletonWithReflection) constructor.newInstance();

        System.out.println("s1 == s2 (via Reflection): " + (s1 == s2)); // 输出: false
        System.out.println("s1: " + s1);
        System.out.println("s2: " + s2);
        // 结果证明,反射创建了新对象,破坏了单例。
    }
}

解决方案: 在私有构造方法中添加防止重复创建的逻辑。

复制代码
class SingletonWithReflectionFixed {
    private static volatile SingletonWithReflectionFixed instance;

    private SingletonWithReflectionFixed() {
        // 1. 在构造方法中添加检查逻辑
        if (instance != null) {
            throw new RuntimeException("单例模式被反射破坏!不允许创建多个实例。");
        }
        System.out.println("SingletonWithReflectionFixed 构造方法被调用...");
    }

    public static SingletonWithReflectionFixed getInstance() {
        if (instance == null) {
            synchronized (SingletonWithReflectionFixed.class) {
                if (instance == null) {
                    instance = new SingletonWithReflectionFixed();
                }
            }
        }
        return instance;
    }
}

// --- 测试修复 ---
class ReflectionFixTest {
    public static void main(String[] args) throws Exception {
        SingletonWithReflectionFixed s1 = SingletonWithReflectionFixed.getInstance();

        Class<?> clazz = SingletonWithReflectionFixed.class;
        Constructor<?> constructor = clazz.getDeclaredConstructor();
        constructor.setAccessible(true);

        try {
            // 尝试通过反射创建第二个实例,会抛出异常
            SingletonWithReflectionFixed s2 = (SingletonWithReflectionFixed) constructor.newInstance();
        } catch (Exception e) {
            System.out.println("捕获异常: " + e.getCause().getMessage()); // 输出异常信息
        }
    }
}

注意: 枚举方式 enum 天然免疫这两种破坏方式。


🔍 JDK 源码解析:Runtime

Runtime 类是 Java 核心库中单例模式的经典应用。

复制代码
public class Runtime {
    // 1. 静态变量在类加载时创建实例,属于饿汉式
    private static Runtime currentRuntime = new Runtime();

    /**
     * Returns the runtime object associated with the current Java application.
     * Most of the methods of class <code>Runtime</code> are instance
     * methods and must be invoked with respect to the current runtime object.
     *
     * @return  the <code>Runtime</code> object associated with the current
     *          Java application.
     */
    // 2. 提供公共静态方法获取实例
    public static Runtime getRuntime() {
        return currentRuntime;
    }

    // 3. 私有构造方法,防止外部实例化
    /** Don't let anyone else instantiate this class */
    private Runtime() {}
    ...
}

// --- 使用示例 ---
class RuntimeDemo {
    public static void main(String[] args) throws IOException {
        // 获取 Runtime 的唯一实例
        Runtime runtime = Runtime.getRuntime();

        // 获取 JVM 内存信息
        System.out.println("Total Memory: " + runtime.totalMemory());
        System.out.println("Max Memory: " + runtime.maxMemory());

        // 执行系统命令 (示例:在 Linux/Mac 上用 'ls' 或 Windows 上用 'dir')
        Process process = runtime.exec("cmd /c dir"); // Windows 示例
        // Process process = runtime.exec("ls -l"); // Linux/Mac 示例

        // 读取命令输出
        try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
            String line;
            while ((line = reader.readLine()) != null) {
                System.out.println(line);
            }
        }
        // 确保进程结束
        process.destroy();
    }
}

📈 单例模式总结

|-------------|------|--------|----|--------|--------|
| 实现方式 | 线程安全 | 懒加载 | 性能 | 推荐度 | 破坏方式 |
| 饿汉式 (静态变量) | ✅ | ❌ | 高 | ⭐⭐⭐ | 序列化、反射 |
| 饿汉式 (静态代码块) | ✅ | ❌ | 高 | ⭐⭐⭐ | 序列化、反射 |
| 懒汉式 (线程不安全) | ❌ | ✅ | 高 | ⭐ | - |
| 懒汉式 (同步方法) | ✅ | ✅ | 低 | ⭐⭐ | 序列化、反射 |
| 懒汉式 (双重检查锁) | ✅ | ✅ | 高 | ⭐⭐⭐⭐⭐ | 序列化、反射 |
| 静态内部类 | ✅ | ✅ | 高 | ⭐⭐⭐⭐⭐ | 序列化、反射 |
| 枚举 | ✅ | ❌ (饿汉) | 高 | ⭐⭐⭐⭐⭐⭐ | 无 |

🎨 选择建议

  • 推荐首选 : 枚举。它是最安全、最简洁的实现,几乎可以应对所有场景。
  • 备选方案 : 静态内部类双重检查锁 (DCL)。它们在性能和安全性之间取得了很好的平衡。
  • 简单场景 : 如果实例不重,且确定不会被破坏,饿汉式 也是不错的选择。

🚫 优缺点

优点:

  • 内存效率: 只有一个实例,减少了内存开销。
  • 资源管理: 避免了对共享资源的重复占用。
  • 全局访问: 提供了一个全局的访问点。

缺点:

  • 扩展性差: 单例类通常没有抽象层,扩展困难。
  • 违反单一职责: 单例类既管理自身实例,又执行业务逻辑。
  • 单元测试难: 由于其全局状态,难以进行单元测试。
相关推荐
阿闽ooo11 小时前
深入浅出适配器模式:从跨国插头适配看接口兼容的艺术
c++·设计模式·适配器模式
Kiyra15 小时前
WebSocket vs HTTP:为什么 IM 系统选择长连接?
分布式·websocket·网络协议·http·设计模式·系统架构·wpf
山沐与山18 小时前
【设计模式】Python责任链模式:从入门到实战
python·设计模式·责任链模式
繁星星繁19 小时前
【项目】基于SDK实现的智能聊天助手(使用api接入deepseek)------(二)
c++·设计模式·学习方法
职业码农NO.119 小时前
系统架构设计中的 15 个关键取舍
设计模式·架构·系统架构·ddd·架构师·设计规范·领域驱动
燕双嘤19 小时前
LLM:RAG,设计模式,Agent框架
人工智能·机器学习·设计模式
阿拉斯攀登20 小时前
设计模式:构建者模式
设计模式·建造者模式·构建者模式
山沐与山20 小时前
【设计模式】Python工厂模式与依赖注入:FastAPI的Depends到底在干嘛
python·设计模式·fastapi
.简.简.单.单.21 小时前
Design Patterns In Modern C++ 中文版翻译 第十一章 享元模式
c++·设计模式·享元模式