4.Android 设计模式 单例模式 Singleton 在项目中的实战

0 阅读5分钟

单例模式:全局唯一实例的优雅实现

摘要:单例模式(Singleton)确保一个类只有一个实例,并提供全局访问点。本文详解其原理、Android应用场景、UML、实战对比及优缺点,助你深入掌握这一核心设计模式。

1.概念

单例模式的核心思想是:

  • 私有化构造函数:禁止外部直接创建实例。
  • 静态私有实例:类内部持有唯一实例的引用。
  • 全局访问点:通过静态方法(如 getInstance())获取实例。

关键代码示例: public class Singleton { private static Singleton instance; // 静态私有实例

private Singleton() {} // 私有构造

public static synchronized Singleton getInstance() {
    if (instance == null) {
        instance = new Singleton(); // 延迟初始化
    }
    return instance;
}

}

2.在Android源码中的应用场景

2.1 LayoutInflater
LayoutInflater inflater = LayoutInflater.from(context);

内部通过单例缓存避免重复创建解析器。

2.2 Retrofit
public class RetrofitClient {
    private static class Holder {
        private static final Retrofit INSTANCE = new Retrofit.Builder()
            .baseUrl(BASE_URL)
            .build();
    }
    public static Retrofit getInstance() {
        return Holder.INSTANCE;
    }
}

3.UML图

     ┌─────────────┐
     │   Singleton │
     ├─────────────┤
     │ - instance  │
     ├─────────────┤
     │ - Singleton()│
     │ + getInstance()│
     └─────────────┘
             ▲
             │
     唯一持有自身实例

单列实现原理图: deepseek_mermaid_20250701_868744.png

  • Singleton:包含静态私有实例 instance
  • 私有构造:防止外部实例化。
  • getInstance() :控制实例创建并提供全局访问。

4.项目的例子和没用设计模式的对比

以下是一个在语音识别项目中应用单例模式的真实示例

语音引擎管理器: 它封装了语音识别、合成和状态管理的核心功能:

4.1 使用单例模式
public class SpeechConstant {
    public static final int TYPE_CLOUD = 1;
    public static final int ENGINE_TYPE = 2;
    public static final String VOICE_NAME = "";
}
public class SpeechSynthesizer {


    public static SpeechSynthesizer createSynthesizer(Object o) {
        return null;
    }

    public void destroy() {
    }

    public boolean isSpeaking() {
        return true;
    }

    public void stopSpeaking() {
    }

    public void startSpeaking(String text, Object o) {
    }

    public void setParameter(String voiceName, String xiaoyan) {
    }
}
public class VoiceEngineManager {
    // 单例实例(volatile保证多线程可见性)
    private static volatile VoiceEngineManager instance;

    // 语音识别引擎
    private SpeechRecognizer recognizer;
    // 语音合成引擎
    private SpeechSynthesizer synthesizer;
    // 当前语音识别状态
    private boolean isRecognizing = false;

    // 私有构造器
    private VoiceEngineManager() {
        initSpeechEngine();
    }

    /**
     * 获取单例实例(双重检查锁实现线程安全)
     */
    public static VoiceEngineManager getInstance() {
        if (instance == null) {
            synchronized (VoiceEngineManager.class) {
                if (instance == null) {
                    instance = new VoiceEngineManager();
                }
            }
        }
        return instance;
    }

    /**
     * 初始化语音引擎
     */
    private void initSpeechEngine() {
        // 初始化语音识别引擎
        recognizer = SpeechRecognizer.createRecognizer( null);
        recognizer.setParameter(SpeechConstant.ENGINE_TYPE, SpeechConstant.TYPE_CLOUD);

        // 初始化语音合成引擎
        synthesizer = SpeechSynthesizer.createSynthesizer(null);
        synthesizer.setParameter(SpeechConstant.VOICE_NAME, "xiaoyan");
    }

    /**
     * 开始语音识别
     */
    public void startRecognition(RecognitionListener listener) {
        if (!isRecognizing) {
            recognizer.startListening(listener);
            isRecognizing = true;
            Log.d("VoiceEngine", "语音识别已启动");
        }
    }

    /**
     * 停止语音识别
     */
    public void stopRecognition() {
        if (isRecognizing) {
            recognizer.stopListening();
            isRecognizing = false;
            Log.d("VoiceEngine", "语音识别已停止");
        }
    }

    /**
     * 语音合成播报
     */
    public void speak(String text) {
        if (synthesizer.isSpeaking()) {
            synthesizer.stopSpeaking();
        }
        synthesizer.startSpeaking(text, null);
    }

    /**
     * 释放引擎资源
     */
    public void release() {
        if (recognizer != null) {
            recognizer.destroy();
        }
        if (synthesizer != null) {
            synthesizer.destroy();
        }
        isRecognizing = false;
    }

    // 语音识别监听器接口
    public interface RecognitionListener {
        void onResults(String result);
        void onError(int errorCode);
    }


    static class Log{


        public static void d(String voiceEngine, String tag) {
        }
    }

}

5.优点

  1. 资源优化:避免重复创建(如数据库连接池)。
  2. 状态一致性:全局唯一实例保证数据准确。
  3. 访问便捷:通过静态方法随处获取实例。
  4. 扩展性:可派生子类实现灵活的单例逻辑(如按线程区分)。

6.和相识的设计模式的区别

基本没有

模式核心目标与单例的区别
静态工具类提供无需实例的公共方法无状态存储,单例可持有成员变量
享元模式复用细粒度对象管理多例,单例仅维护唯一实例
依赖注入解耦对象创建与使用单例主动控制实例,DI由容器管理实例
6.2 单例模式的几种类型
6.2.1 双重检查锁 (DCL)
public class DCLSingleton {
    // volatile保证可见性和禁止指令重排序
    private static volatile DCLSingleton instance;
    
    private DCLSingleton() {
        // 防止反射攻击
        if (instance != null) {
            throw new IllegalStateException("Already initialized");
        }
    }
    
    public static DCLSingleton getInstance() {
        // 第一次检查(无锁)
        if (instance == null) {
            synchronized (DCLSingleton.class) {
                // 第二次检查(加锁后)
                if (instance == null) {
                    instance = new DCLSingleton();
                }
            }
        }
        return instance;
    }
}
6.2.1.1 为什么要2次判空?

核心目的:性能优化与线程安全的完美平衡

双重判空的必要性:

  1. 第一层判空(无锁检查)

    • 解决99%的读操作性能问题
    • 当实例已存在时,直接返回(避免锁竞争)
    • 减少同步块执行次数(性能提升5-100倍)
  2. 第二层判空(同步块内检查)

    • 防止重复创建实例
    • 处理首次初始化时的竞态条件
    • 确保多线程环境下仅创建唯一实例

deepseek_mermaid_20250701_d9db8b.png

6.2.1.2 为什么要用synchronized?

核心作用:解决写操作的原子性

创建过程非原子: 多个线程

6.2.1.3 为什么要用volatile?
禁止指令重排序
// 无volatile时可能发生的错误场景:
Thread A: 
    instance = new Singleton(); // 步骤2和3重排1.分配内存
    → 3.赋值引用 (此时instance!=null)
    → 2.初始化对象 (未完成)
    
Thread B:
    if (instance != null) 
        // 使用未初始化的对象 → NPE!
6.2.2 静态内部类 (DCL)
public class HolderSingleton {
    private HolderSingleton() {
        // 防止反射攻击
        if (Holder.INSTANCE != null) {
            throw new IllegalStateException("Already initialized");
        }
    }
    
    public static HolderSingleton getInstance() {
        return Holder.INSTANCE;
    }
    
    // 静态内部类在首次调用getInstance()时加载
    private static class Holder {
        private static final HolderSingleton INSTANCE = new HolderSingleton();
    }
}
6.2.3 枚举单例 (DCL)
public enum EnumSingleton {
    INSTANCE;
    
    // 业务方法
    public void doSomething() {
        System.out.println("Enum Singleton Working");
    }
}

单例的3种模式的对比:

版本线程安全防反射防序列化延迟加载适用场景
双重检查锁 (DCL)高并发服务端
静态内部类Android/桌面应用
枚举单例分布式系统/安全敏感场景

总结:单例模式是控制实例数量的利器,尤其在需要全局状态管理(如配置、缓存)的场景中不可替代。但需警惕滥用——过度使用会导致代码耦合,建议结合依赖注入框架(如Dagger)优化架构。

项目的地址: github.com/pengcaihua1…