答案 0 :(得分:1)
我建议首先实施“穷人的DI”模式。这是你在类中定义两个构造函数的地方,一个接受依赖项的实例(IoC),另一个是new的新构造函数(或调用单例)。
通过这种方式,您可以逐步引入IoC,并且仍然可以使用默认构造函数来完成其他所有操作。最终,当您在大多数地方使用IoC时,您可以开始删除默认构造函数(和单例)。
public class Foo {
public Foo(ILogger log, IConfig config) {
_logger = log;
_config = config;
}
public Foo() : this(Logger.Instance(), Config.Instance()) {}
}
答案 1 :(得分:1)
通常,您应该尝试将上下文信息包装到自己的实例中,并提供静态访问器方法来引用它。例如,通过HttpContext
考虑HttpContext.Current
及其在Web应用程序中的每个位置都可用。
您应该尝试设计类似的东西,以便不是返回单例实例,而是从当前上下文返回实例。这样,您就不需要更改引用这些静态方法的消费者代码(例如Logger.Instance()
)。
我通常将记录器,当前用户,配置,安全权限等信息汇总到应用程序上下文中(如果需要,可以是多个类)。 AppContext.Current
静态方法返回当前上下文。方法实现类似于
public interface IContextStorage
{
// Gets the stored context
AppContext Get();
// Stores the context, context can be null
void Set(AppContext context);
}
public class AppContext
{
private static IContextStorage _storageProvider, _defaultStorageProvider;
public static AppContext Current
{
get
{
var value = _storageProvider.Get();
// If context is not available in storage then lookup
// using default provider for worker (threadpool) therads.
if (null == value && _storageProvider != _defaultStorageProvider
&& Thread.CurrentThread.IsThreadPoolThread)
{
value = _defaultStorageProvider.Get();
}
return value;
}
}
...
}
IContextStorage
实现是特定于应用程序的。静态变量_storageProvider
在应用程序启动时注入,而_defaultStorageProvider
是一个查看当前调用上下文的简单实现。
应用程序上下文创建分多个阶段进行 - 例如,配置等全局信息在应用程序启动时被读取和缓存,而特定信息如用户和安全性在认证阶段形成。一旦所有信息都可用,就会创建实际实例并将其存储到特定于应用程序的存储位置。例如,桌面应用程序将使用单例实例,而Web应用程序可能会将实例存储到会话状态。对于Web应用程序,您可以在每个请求的开头都有逻辑,以确保初始化上下文。
对于可伸缩的Web应用程序,您可以拥有一个存储提供程序,它将上下文实例存储到缓存中,如果不存在于缓存中,则重新构建它。