一般而言,大多数依赖项可以在创建时注入到您的类中。但是,在这种特殊情况下,您需要一个必须在使用时按需创建的组件。在这种情况下,完全删除对IoC容器的依赖是非常困难的。我的方法一直是创建一个在创建时注入到类中的工厂,这反过来又封装了所有直接的IoC用法。这样就可以模拟来测试你的工厂,而不是IoC容器本身......这往往是一个容易得多:
// In Presentation.csproj
class PresentationController
{
public PresentationController(IDataContextFactory dataContextFactory, IRepositoryFactory repositoryFactory)
{
#region .NET 4 Contract
Contract.Requires(dataContextFactory != null);
Contract.Requires(repositoryFactory != null);
#endregion
_dataContextFactory = dataContextFactory;
_repositoryFactory = repositoryFactory;
}
private readonly IDataContextFactory _dataContextFactory;
private readonly IRepositoryFactory _repositoryFactory;
public void Action()
{
using (IDataContext dc = _dataContextFactory.CreateInstance())
{
var repo = _repositoryFactory.CreateUserRepository();
// do stuff with repo...
}
}
}
// In Factories.API.csproj
interface IDataContextFactory
{
IDataContext CreateInstance();
}
interface IRepositoryFactory
{
IUserRepository CreateUserRepository();
IAddressRepository CreateAddressRepository();
// etc.
}
// In Factories.Impl.csproj
class DataContextFactory: IDataContextFactory
{
public IDataContext CreateInstance()
{
var context = IoC.Resolve<IDataContext>();
// Do any common setup or initialization that may be required on 'context'
return context;
}
}
class RepositoryFactory: IRepositoryFactory
{
public IUserRepository CreateUserRepository()
{
var repo = IoC.Resolve<IUserRepository>();
// Do any common setup or initialization that may be required on 'repo'
return repo;
}
public IAddressRepository CreateAddressRepository()
{
var repo = IoC.Resolve<IAddressRepository>();
// Do any common setup or initialization that may be required on 'repo'
return repo;
}
// etc.
}
这种方法的好处是,虽然你不能完全消除IOC依赖本身,您可以将其封装在单一类型的对象(工厂)中,将大部分代码与IoC容器解耦。例如,从一个IoC容器切换到另一个(即Windsor到Ninject),这可以提高您的代码敏捷性。
应该指出,这样做的一个有趣的结果是,你的工厂通常是通过它们使用的相同的IoC框架注入到他们的家属。例如,如果您正在使用Castle Windsor,则可以创建配置,告诉IoC容器在创建时将两个工厂注入到业务组件中。业务组件本身也可能有一个工厂......或者它可以简单地由相同的IoC框架注入到一个更高级别的组件中,等等。
感谢您的回答。唯一的问题是我使用的IoC应该有一个相对于'using'语句的范围。然后,如果我解析说'IDataContext'它将解决该特定范围的*单个实例*。我不希望我的控制器等意识到IoC容器,但是真的有办法解决这个问题吗? – TheCloudlessSky 2010-07-01 10:54:44
我想知道如果一个控制器应该能够调用IoC.Resolve?如果不是,谁应该打这个电话? –
TheCloudlessSky
2010-07-01 12:01:07
你能解释一下这个范围吗?您使用的是什么IoC容器?一般来说,以任何方式将任何代码耦合到容器框架是一种消极的耦合方式......您应该不惜一切代价避免这种情况。根据我的经验,范围(或上下文)很少(如果有的话)需要IoC容器工作。如果它以这种方式工作,我会找到一个替代容器,或者找到一种方法将这种上下文提供给解决您的对象的工厂,并尽可能保持您的IoC框架解耦。 – jrista 2010-07-01 16:24:38