【发布时间】:2016-01-06 20:29:23
【问题描述】:
此问题与 Android 有关,但也可以在其他情况下提出。我需要创建一个暴露单例的库;或者我想确保我的类只存在一个实例,并且可以在代码中的任何位置抓取而不传递引用。
但是那些单例需要一些参数。例如,在 Android 中,经常需要 Context 对象。我还必须准确地说,由于我提供了一个库,我希望用户可以轻松使用 我无法控制 Android 中的 Application 类(这个类有时可用于管理整个应用的对象实例)。
一种已知的解决方案是执行以下操作:
static MySingleton sInstance;
MySingleton.getInstance(Context c) {
if (sInstance == null) {
sInstance = new MySingleton(c.getApplicationContext());
}
return sInstance;
}
但很奇怪,getInstance 的参数实际上只在第一次创建单例时使用。
我可以为单例提供一个setter,并要求开发者正确设置所需的参数,但可能会出现一些奇怪的情况:
// Good usage
MySingleton.getInstance().setContext(context.getApplicationContext());
MySingleton.getInstance().doSomethingThatRequiresContext(); // OK
// Bad usage
MySingleton.getInstance().doSomethingThatRequiresContext(); // Error!
MySingleton.getInstance().setContext(context.getApplicationContext());
我可以在每个方法的开头检查单例是否正确配置,并在状态不佳时启动一些异常,但 API 使用起来不太简单:
MySingleton.getInstance().setContext(context.getApplicationContext());
try {
MySingleton.getInstance().doSomethingThatRequiresContext();
}
catch(BadSingletonConfiguration e) { }
即使我使用运行时异常,使用起来也会很危险。
除非我恳请用户手动创建实例并确保自己只存在一个实例,否则我看不到好的解决方案。
【问题讨论】:
-
也许使用不可变对象.... Java String 被实现为不可变。
-
请注意,如果在线程中引用单例,则以下每个示例都会发生内存泄漏。您必须使用 WeakReference 来存储上下文,否则您的上下文将不会被 GC 处理。
-
如果您写上下文,通常会执行 getApplicationContext() 以拥有包含整个活动生命周期的上下文,因此在应用程序运行时它不会被 GC。如果您愿意,我可以修改示例。
标签: java android oop design-patterns