Ответ 1
Вообще говоря, большинство зависимостей могут быть введены в ваш класс в момент его создания. Однако в этом конкретном случае вам нужен компонент, который должен быть создан по требованию во время использования. В таких случаях очень сложно полностью удалить зависимость от контейнера IoC. Мой подход всегда заключался в создании factory, который вводится в класс во время создания, что, в свою очередь, инкапсулирует все прямое использование 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, вы можете инкапсулировать его в один вид объекта (a factory), развязывая основную часть вашего кода из контейнера IoC. Это повышает гибкость ваших кодов в свете, скажем, перехода от одного контейнера IoC к другому (например, Windsor to Ninject).
Следует отметить, что интересным последствием этого является то, что ваши заводы обычно вводятся в их иждивенцы той же картой IoC, которую они используют. Например, если вы используете Castle Windsor, вы должны создать конфигурацию, которая сообщает контейнеру IoC вставлять две фабрики в ваш бизнес-компонент при его создании. Сам бизнес-компонент также может иметь factory... или его можно просто ввести одной картой IoC в компонент более высокого уровня и т.д. И т.д., Ad inf.