【问题标题】:What is the difference between the implementation of singleton on Dependency Injection frameworks (like Dagger) than the normal static singleton?在依赖注入框架(如 Dagger)上实现单例与普通静态单例有什么区别?
【发布时间】:2025-12-30 17:25:12
【问题描述】:

我刚刚和一个朋友进行了一次简短的交谈,他坚持认为用于 Dagger 的单例比通过老式静态私有变量方式制作一个更好。并不是说我确定他错了,我只是想弄清楚为什么更好。

这两种实现方式(DI vs 普通静态)有什么区别?

【问题讨论】:

  • 我相信最不坏的方法是使用enum

标签: java android singleton dagger


【解决方案1】:

Java best practices book 解释了为什么您应该使用私有属性来强制执行 Singleton 属性 构造函数或枚举类型。这一章比较长,总结一下吧:

使一个类成为单例可以 难以测试其客户端,因为无法替代模拟实现 对于单例,除非它实现了用作其类型的接口。 在 1.5 版之前,有两种方法可以实现单例。两者都是 基于保持构造函数私有并将公共静态成员导出到 提供对唯一实例的访问。在一种方法中,成员是最终字段:

// Singleton with public final field
public class Elvis {
public static final Elvis INSTANCE = new Elvis();
private Elvis() { ... }
public void leaveTheBuilding() { ... }
}

在实现单例的第二种方法中,公共成员是 静态工厂方法:

// Singleton with static factory
public class Elvis {
private static final Elvis INSTANCE = new Elvis();
private Elvis() { ... }
public static Elvis getInstance() { return INSTANCE; }
public void leaveTheBuilding() { ... }
}

还有第三种实现单例的方法。通过简单 用一个元素创建一个枚举类型:

// Enum singleton - the preferred approach
public enum Elvis {
INSTANCE;
public void leaveTheBuilding() { ... }
}

此方法在功能上等同于公共字段方法,不同之处在于它 更简洁,免费提供序列化机制,并提供 对多次实例化的铁定保证,即使面对复杂的 序列化或反射攻击。

虽然这种方法尚未广泛应用 采用单元素枚举类型是实现单例的最佳方式。

【讨论】: