暂时搁置一下关于Singleton模式的相对优点和缺点的论点,并考虑到Singleton通常被认为是一个在应用程序的生命周期中持续存在的实例,那么最好的方法是什么?有一个生命有限的单身人士?
是否有类似以下内容的错误:
public class CategoryHandler
{
private static DateTime m_expires;
public bool HasExpired
{
get return DateTime.Now > m_expires;
}
private CategoryHandler()
{
m_expires = DateTime.Now.AddMinutes(60);
}
public static CategoryHandler Instance()
{
if(HasExpired)
{
//Dispose and reconstruct
}
else
{
//Use existing instance
}
}
}
或者有更好的方法来解决这个问题吗?
答案 0 :(得分:4)
您需要某种锁定来确保线程安全:
public sealed class CategoryHandler
{
private static CategoryHandler _instance = null;
private static DateTime _expiry = DateTime.MinValue;
private static readonly object _lock = new object();
private CategoryHandler() { }
public static bool HasExpired
{
get
{
lock (_lock) { return (_expiry < DateTime.Now); }
}
}
public static CategoryHandler Instance
{
get
{
lock (_lock)
{
if (HasExpired)
{
// dispose and reconstruct _instance
_expiry = DateTime.Now.AddMinutes(60);
}
return _instance;
}
}
}
}
答案 1 :(得分:2)
我能看到的唯一主要问题是,另一个类已经有了对旧实例的引用,这不会使它失效。所以只要所有类都这样做:
CategoryHandler.Instance.Method();
而不是
CategoryHandler singleton = CategoryHandler.Instance;
...
singleton.SomeMethod();
你应该没事,只要你对单身人士下次被引用而不是在六十分钟之后过期感到高兴。
如果你需要它在一段时间之后到期,那么你将需要使用一个计时器并在回调方法中替换实例(注意计时器将在另一个线程中回调,所以一定要实现一个线程安全的单身人士模式)
答案 2 :(得分:2)
为了避免类引用旧实例的问题,您可以考虑为您的类编写缓存包装器。 Fist提取接口ICategoryHandler,假设它看起来像这样:
interface ICategoryHandler
{
int A();
}
然后实现包装器(省略锁定):
class CategoryHandlerWrapper : ICategoryHandler
{
ICategoryHandler instance;
private DateTime expiry = DateTime.MinValue;
public int A()
{
return Instance().A();
}
public bool HasExpired
{
get return DateTime.Now > expiry;
}
private CategoryHandler Instance()
{
if(HasExpired)
{
//Dispose and reconstruct
}
else
{
//Use existing instance
}
}
}
通过这种方式,您可以使用普通依赖注入,并仍然享受您所追求的功能。此外,旧引用的问题也封装在一个地方。
答案 3 :(得分:1)
您是否考虑过使用IoC/DI Container framework并让它管理“单身人士”的生命周期?
微软的Unity是我最熟悉的,他们没有提供开箱即用的LifetimeManager,它完全符合您的要求。但是,你可以创建自己的后代;见Writing Custom Lifetime Managers。
或者您可以查看其他框架,看看框中是否有您想要的内容。
编辑:请注意,这仍然不能让你摆脱马丁提到的“捕获”问题。
答案 4 :(得分:0)
你想用即将到期的单身人士到底想要达到什么目的?如果你真的想这样做,我认为你的设计有问题。正如马丁所说,如果某些代码“捕获”了你的单例实例,你就会遇到麻烦。
那么,您对此有何用处?或者问题出于好奇心?